林旭祥 hai 8 meses
pai
achega
cf9d27e4a7

+ 1 - 1
src/utils/handController.ts

@@ -3,7 +3,7 @@ const address: any = import.meta.env.VITE_APP_BASE_API;
 const token: any = localStorage.getItem('token');
 let socket: any = {}; //ws实例对象
 
-export const initWs = (callback: any) => {
+export const handWs = (callback: any) => {
   socket = io(address + '/', {
     transports: ['websocket', 'polling'],
     query: {

+ 30 - 11
src/views/gesture/index.vue

@@ -2,8 +2,8 @@
   <div class="gesture">
     <Header :showClose="false" :showTool="false"></Header>
     <div class="menu">
-      <swiper v-if="projectList.length" ref="mySwiper" :slides-per-view="5" :space-between="0" :initialSlide="2"
-        :loop="true" :centeredSlides="true">
+      <swiper v-if="projectList.length" :slides-per-view="5" :space-between="0" :initialSlide="2" :loop="true"
+        :centeredSlides="true" :modules="[Navigation]" @swiper="onSwiper">
         <swiper-slide v-for="(item, index) in projectList " :key="index">
           <div class="li">
             <div class="pic"><img :src="'static/images/train/' + item.key + '.png'"></div>
@@ -18,17 +18,14 @@
 </template>
 
 <script setup name="Gesture" lang="ts">
-import { initWs } from '@/utils/handController'
+import { handWs } from '@/utils/handController'
 import { Swiper, SwiperSlide } from 'swiper/vue';
-import { Navigation, Pagination } from 'swiper/modules';
+import { Navigation } from 'swiper/modules';
 import 'swiper/css';
 import 'swiper/scss/navigation';
-import 'swiper/scss/pagination';
-
-const mySwiper = ref(null);
 const router = useRouter();
 const { proxy } = getCurrentInstance() as any;
-
+const mySwiper = ref(null);
 const data = reactive<any>({
   projectList: [],
   timerManager: {},
@@ -70,12 +67,33 @@ const getExam = async () => {
   });
 };
 
+/**
+ * 获取实例
+*/
+const onSwiper = ($ev) => {
+  mySwiper.value = $ev;
+};
+
+/**
+ * 切换上一页
+*/
+const slidePrev = () => {
+  mySwiper.value.slidePrev();
+};
+
+/**
+ * 切换下一页
+*/
+const slideNext = () => {
+  mySwiper.value.slideNext();
+};
+
 onBeforeMount(() => {
-  //加载WS
-  initWs((e: any) => {
+  //加载手势WS
+  handWs((e: any) => {
     //左滑动
     if (e.data.result == "next_item") {
-
+      slideNext();
     }
     //举左手
     if (e.data.result == "left_hand") {
@@ -89,6 +107,7 @@ onBeforeMount(() => {
   getInitExam();
 })
 onMounted(() => {
+
 })
 onUnmounted(() => {
   getClearTimer();

+ 21 - 5
src/views/set/index.vue

@@ -9,7 +9,6 @@
             部署
           </div>
         </div>
-
       </div>
       <div class="li" @click="getLogout">
         <div class="liBox">
@@ -19,11 +18,20 @@
           </div>
         </div>
       </div>
+      <div class="li" @click="getGesture">
+        <div class="liBox">
+          <div class="pic"><img src="@/assets/images/common/set2.png"></div>
+          <div class="name">
+            手势项目入口
+          </div>
+        </div>
+      </div>
     </div>
-    <div style=" color: #ffffff; font-size:2rem">
-      <div @click="getCmdtest(1)">左滑动</div>
-      <div @click="getCmdtest(2)">举左手</div>
-      <div @click="getCmdtest(3)">双手胸前交叉</div>
+    <div style=" color: #ffffff; font-size:2rem; text-align: center;">
+      发送手势:
+      <div @click="getCmdtest(1)">1、左滑动</div>
+      <div @click="getCmdtest(2)">2、举左手</div>
+      <div @click="getCmdtest(3)">3、双手胸前交叉</div>
     </div>
   </div>
 </template>
@@ -65,6 +73,14 @@ const getCmdtest = (data: any) => {
   });
 };
 
+/**
+ * 返回
+*/
+const getGesture = () => {
+  router.push({ path: '/gesture' });
+};
+
+
 /**
  * 返回
 */

+ 82 - 2
src/views/train/multiple.vue

@@ -67,6 +67,7 @@
 <script setup name="Multiple" lang="ts">
 import { initSpeech, speckText, speckCancel, chineseNumber } from '@/utils/speech'
 import { initWs, examEnds, openOneTest, startFace, stopFace, faceConfirmOnly, startOneTest, finishOneTest, closeOneTest, suspendFaceRecognitionChannels, resumeFaceRecognitionChannels } from '@/utils/ws'
+import { handWs } from '@/utils/handController'
 const { proxy } = getCurrentInstance() as any;
 const router = useRouter();
 const route = useRoute();
@@ -87,8 +88,9 @@ const data = reactive<any>({
   multipleItemRefList: [],//获取区列表
   styleType: null,//展示样式1:1-5个,2:6-10个,3:10个以上
   showReportList: false,//显示隐藏测试记录
+  exit: 0,//退出响应次数
 });
-const { timerManager, parameter, time, userInfo, examState, needStart, showTestAgain, testList, multipleItemRefList, styleType, showReportList } = toRefs(data);
+const { timerManager, parameter, time, userInfo, examState, needStart, showTestAgain, testList, multipleItemRefList, styleType, showReportList, exit } = toRefs(data);
 
 /**
  * 创建组件实例
@@ -375,6 +377,19 @@ const returnData = (data: any) => {
  * 准备开始
 */
 const getReady = () => {
+  if (examState.value != 43) {
+    return false;
+  }
+  let flag = false;
+  for (let i = 0; i < testList.value.length; i++) {
+    if (testList.value[i] && testList.value[i].faceCheckStu?.student_id) {
+      flag = true;
+    }
+  }
+  if (!flag) {
+    proxy?.$modal.msgWarning("请选择人员!");
+    return false;
+  }
   //停止播报;
   speckCancel()
   //正在识别的停止识别
@@ -452,6 +467,69 @@ const getAddTestList = (num: number) => {
   }
 };
 
+/**
+ * 加载手势WS
+*/
+const initHand = () => {
+  handWs((e: any) => {
+    //左滑动
+    if (e.data.result == "next_item") {
+    }
+    //举左手
+    if (e.data.result == "left_hand") {
+      getReady();
+    }
+    //退出
+    if (e.data.result == "exit") {
+      // console.log("exit.value", exit.value)
+      if (exit.value == 0) {
+        console
+        //第一次才弹出
+        confirmExit();
+        setTimeout(() => {
+          let keyEvent = null;
+          let myKey = null;
+          //如果交叉手两秒后返回超过4次就确认退出
+          if (exit.value >= 4) {
+            myKey = 'Enter';
+          } else {
+            myKey = 'Esc';
+            exit.value = 0;
+          }
+          if (myKey == 'Esc') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Escape', // 键值
+              code: 'Escape', // 键盘代码
+              keyCode: 27, // 旧的键盘代码
+              which: 27, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          if (myKey == 'Enter') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Enter', // 键值
+              code: 'Enter', // 键盘代码
+              keyCode: 13, // 旧的键盘代码
+              which: 13, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          document.activeElement.dispatchEvent(keyEvent);
+        }, 2500)
+      }
+      exit.value = exit.value + 1
+    }
+  });
+};
+
 /**
  * 播报时间
 */
@@ -521,7 +599,6 @@ onBeforeMount(() => {
   }
 })
 
-
 onMounted(() => {
   //加载WS
   let project = parameter.value.project;
@@ -532,7 +609,10 @@ onMounted(() => {
     })
     multipleItemRefList.value[index]?.getMessage(data);
   });
+  //初始化语音
   initSpeech();
+  //初始化手势
+  initHand();
   setTimeout(() => {
     //10秒还在0状态就算超时
     if (examState.value == 0) {

+ 99 - 7
src/views/train/run.vue

@@ -4,13 +4,14 @@
     <Transition :enter-active-class="proxy?.animate.dialog.enter" :leave-active-class="proxy?.animate.dialog.leave">
       <div class="time" v-show="[42].includes(examState)">{{
         countdownNumFormat
-        }}</div>
+      }}</div>
     </Transition>
     <div class="main">
       <template v-if="isLongRun">
         <!--长跑-->
         <swiper :slides-per-view="testListArr.length >= 2 ? 2 : 1" :slides-per-group="testListArr.length >= 2 ? 2 : 1"
-          :space-between="20">
+          :space-between="20" :speed="1200" :modules="[Navigation]"
+          :navigation="{ prevEl: '.swiper-button-prev', nextEl: ' .swiper-button-next' }">
           <swiper-slide v-for="(items, indexs) in testListArr " :key="indexs">
             <div class="main-left main-left2">
               <div class="trackItem">
@@ -48,6 +49,11 @@
             </div>
           </swiper-slide>
         </swiper>
+        <!-- 如果需要导航按钮 -->
+        <div v-show="testListArr.length > 2" class="swiper-button-prev swiper-btn swiper-btn-left" slot="button-prev">
+        </div>
+        <div v-show="testListArr.length > 2" class="swiper-button-next swiper-btn swiper-btn-right" slot="button-next">
+        </div>
       </template>
       <template v-else>
         <!--短跑-->
@@ -58,12 +64,10 @@
                 <div class="left">
                   <div class="track">{{ item.track }}</div>
                   <div class="userInfo" @click="getChooseStudent(item.track)">
-
                     <div class="pic pic2" v-if="item.student_id"> <img :src="item.face_pic" /></div>
                     <div class="pic" v-else>
                       <img src="@/assets/images/test/profilePicture.png" />
                     </div>
-
                     <div class="nameBox">
                       <div class="name">{{ item.student_name || "未检录" }}</div>
                     </div>
@@ -113,12 +117,13 @@
 <script setup name="TrainTest" lang="ts">
 import { initSpeech, speckText, speckCancel, chineseNumber } from '@/utils/speech'
 import { initWs, examEnds, openOneTest, startFace, stopFace, faceConfirmOnly, startOneTest, finishOneTest, closeOneTest, suspendFaceRecognitionChannels, resumeFaceRecognitionChannels } from '@/utils/ws'
+import { handWs } from '@/utils/handController'
 import dayjs from 'dayjs'
 import dataDictionary from "@/utils/dataDictionary"
 import { Swiper, SwiperSlide } from 'swiper/vue';
-import { Grid } from 'swiper/modules';
+import { Navigation } from 'swiper/modules';
 import 'swiper/css';
-import 'swiper/css/grid';
+import 'swiper/scss/navigation';
 const { proxy } = getCurrentInstance() as any;
 const router = useRouter();
 const route = useRoute();
@@ -141,8 +146,9 @@ const data = reactive<any>({
   showTestAgain: false,//再测一次按钮
   isLongRun: false,//是否为长跑项目
   isBackRun: false,//是否为折返跑项目
+  exit: 0,//退出响应次数
 });
-const { timerManager, parameter, time, userInfo, examState, resultId, faceStudentList, currentTrack, unit, needStart, showTestAgain, isLongRun, isBackRun } = toRefs(data);
+const { timerManager, parameter, time, userInfo, examState, resultId, faceStudentList, currentTrack, unit, needStart, showTestAgain, isLongRun, isBackRun, exit } = toRefs(data);
 
 /**
  * 接收消息
@@ -766,6 +772,69 @@ const faceStudentListLongRun: any = computed(() => {
   }
 });
 
+/**
+ * 加载手势WS
+*/
+const initHand = () => {
+  handWs((e: any) => {
+    //左滑动
+    if (e.data.result == "next_item") {
+    }
+    //举左手
+    if (e.data.result == "left_hand") {
+      getStartOneTest();
+    }
+    //退出
+    if (e.data.result == "exit") {
+      // console.log("exit.value", exit.value)
+      if (exit.value == 0) {
+        console
+        //第一次才弹出
+        confirmExit();
+        setTimeout(() => {
+          let keyEvent = null;
+          let myKey = null;
+          //如果交叉手两秒后返回超过4次就确认退出
+          if (exit.value >= 4) {
+            myKey = 'Enter';
+          } else {
+            myKey = 'Esc';
+            exit.value = 0;
+          }
+          if (myKey == 'Esc') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Escape', // 键值
+              code: 'Escape', // 键盘代码
+              keyCode: 27, // 旧的键盘代码
+              which: 27, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          if (myKey == 'Enter') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Enter', // 键值
+              code: 'Enter', // 键盘代码
+              keyCode: 13, // 旧的键盘代码
+              which: 13, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          document.activeElement.dispatchEvent(keyEvent);
+        }, 2500)
+      }
+      exit.value = exit.value + 1
+    }
+  });
+};
+
 onBeforeMount(() => {
   parameter.value = route.query;
   let project = parameter.value.project;
@@ -799,7 +868,10 @@ onBeforeMount(() => {
   initWs({ parameter: parameter.value, testTime: time.value.testTime }, (data: any) => {
     getMessage(data);
   });
+  //初始化语音
   initSpeech();
+  //初始化手势
+  initHand();
 })
 
 onUnmounted(() => {
@@ -1027,6 +1099,26 @@ $waiPadding: 6.51rem;
     flex-direction: column;
     overflow: hidden;
   }
+
+  .swiper-btn {
+    width: 2.5rem;
+    height: 2.5rem;
+    display: block;
+
+    &::after {
+      display: none;
+    }
+  }
+
+  .swiper-btn-left {
+    background: url("@/assets/images/ranking/btn-left.png") left center no-repeat;
+    background-size: 100% 100%;
+  }
+
+  .swiper-btn-right {
+    background: url("@/assets/images/ranking/btn-right.png") left center no-repeat;
+    background-size: 100% 100%;
+  }
 }
 
 .footerBtn {

+ 83 - 13
src/views/train/test.vue

@@ -21,7 +21,7 @@
               :leave-active-class="proxy?.animate.dialog.leave">
               <div class="time" v-show="needStart && [42].includes(examState)">{{
                 time.countdownNum
-              }}</div>
+                }}</div>
             </Transition>
             <div class="tips" v-if="examState == 41">
               <img v-if="parameter.gesture" src="@/assets/images/test/ready1.png" />
@@ -115,6 +115,7 @@
 <script setup name="TrainTest" lang="ts">
 import { initSpeech, speckText, speckCancel, chineseNumber } from '@/utils/speech'
 import { initWs, examEnds, openOneTest, startFace, stopFace, faceConfirmOnly, startOneTest, finishOneTest, closeOneTest, suspendFaceRecognitionChannels, resumeFaceRecognitionChannels } from '@/utils/ws'
+import { handWs } from '@/utils/handController'
 import dayjs from 'dayjs'
 import dataDictionary from "@/utils/dataDictionary"
 const { proxy } = getCurrentInstance() as any;
@@ -144,8 +145,9 @@ const data = reactive<any>({
   needStart: false,//是否需要按钮
   showTestAgain: false,//再测一次按钮
   readyState: true,//倒计时按钮状态
+  exit: 0,//退出响应次数
 });
-const { timerManager, parameter, time, userInfo, examState, resultId, faceCheckStu, currentResultObj, unit, backReason, backReasonStr, needStart, showTestAgain, readyState } = toRefs(data);
+const { timerManager, parameter, time, userInfo, examState, resultId, faceCheckStu, currentResultObj, unit, backReason, backReasonStr, needStart, showTestAgain, readyState, exit } = toRefs(data);
 
 /**
  * 接收消息
@@ -359,7 +361,7 @@ const getAgain = async () => {
  * 确认退出
 */
 const confirmExit = () => {
-  proxy?.$modal.confirm("确定退出吗?").then(() => {
+  let abc = proxy?.$modal.confirm("确定退出吗?").then(() => {
     getExit();
   }).finally(() => {
   });
@@ -629,18 +631,83 @@ const getAchievement = (data: any) => {
  * 准备开始
 */
 const getReady = () => {
-  speckCancel();
-  readyState.value = false;
-  time.value.ready = 5;
-  speckText(time.value.ready);
-  timerManager.value.readyTimer = setInterval(() => {
-    time.value.ready--;
+  if (needStart.value && examState.value == 43 && !time.value.ready && readyState.value) {
+    speckCancel();
+    readyState.value = false;
+    time.value.ready = 5;
     speckText(time.value.ready);
-    if (time.value.ready == 0) {
-      getClearTimer("readyTimer");
-      getStartOneTest();
+    timerManager.value.readyTimer = setInterval(() => {
+      time.value.ready--;
+      speckText(time.value.ready);
+      if (time.value.ready == 0) {
+        getClearTimer("readyTimer");
+        getStartOneTest();
+      }
+    }, 1000);
+  }
+};
+
+/**
+ * 加载手势WS
+*/
+const initHand = () => {
+  handWs((e: any) => {
+    //左滑动
+    if (e.data.result == "next_item") {
     }
-  }, 1000);
+    //举左手
+    if (e.data.result == "left_hand") {
+      getReady();
+    }
+    //退出
+    if (e.data.result == "exit") {
+      // console.log("exit.value", exit.value)
+      if (exit.value == 0) {
+        console
+        //第一次才弹出
+        confirmExit();
+        setTimeout(() => {
+          let keyEvent = null;
+          let myKey = null;
+          //如果交叉手两秒后返回超过4次就确认退出
+          if (exit.value >= 4) {
+            myKey = 'Enter';
+          } else {
+            myKey = 'Esc';
+            exit.value = 0;
+          }
+          if (myKey == 'Esc') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Escape', // 键值
+              code: 'Escape', // 键盘代码
+              keyCode: 27, // 旧的键盘代码
+              which: 27, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          if (myKey == 'Enter') {
+            keyEvent = new KeyboardEvent('keydown', {
+              key: 'Enter', // 键值
+              code: 'Enter', // 键盘代码
+              keyCode: 13, // 旧的键盘代码
+              which: 13, // 新的键盘代码
+              shiftKey: false, // 是否按下Shift键
+              ctrlKey: false, // 是否按下Ctrl键
+              metaKey: false, // 是否按下Meta键(Win键或Command键)
+              bubbles: true, // 事件是否冒泡
+              cancelable: true // 是否可以取消事件的默认行为
+            });
+          }
+          document.activeElement.dispatchEvent(keyEvent);
+        }, 2500)
+      }
+      exit.value = exit.value + 1
+    }
+  });
 };
 
 /**
@@ -725,7 +792,10 @@ onBeforeMount(() => {
   initWs({ parameter: parameter.value, testTime: time.value.testTime }, (data: any) => {
     getMessage(data);
   });
+  //初始化语音
   initSpeech();
+  //初始化手势
+  initHand();
 })
 
 onUnmounted(() => {