林旭祥 4 settimane fa
parent
commit
003a9a84f9

+ 163 - 0
src/components/OnlineFaceWindow/index.vue

@@ -0,0 +1,163 @@
+<template>
+  <div>
+    <!-- <Transition :enter-active-class="proxy?.animate.mask.enter" :leave-active-class="proxy?.animate.mask.leave">
+      <div class="mask" v-show="faceState"></div>
+    </Transition> -->
+    <Transition :enter-active-class="proxy?.animate.face.enter" :leave-active-class="proxy?.animate.face.leave">
+      <div class="confirmDiaBg" v-show="faceState">
+        <div class="confirmDiaWindow">
+          <div class="confirmDiaWindow-con">
+            <div class="pic" :class="{ 'pic2': faceCheckStu.student_id }" v-if="faceCheckStu.student_id"> <img
+                :src="faceCheckStu.student_icon" /></div>
+            <div class="pic" v-else>
+              <div class="shine">
+                <img src="@/assets/images/common/shine.png" />
+              </div>
+              <img src="@/assets/images/test/profilePicture.png" />
+            </div>
+            <div class="name" :class="{ 'name2': faceCheckStu.student_id }">
+              请看摄像头进行人脸识别
+            </div>
+          </div>
+        </div>
+      </div>
+    </Transition>
+  </div>
+
+</template>
+<script setup lang="ts">
+import { useWebSocket } from '@/utils/faceWs';
+const { faceWs, checkFace, openFace, terminateFace, suspendFace, resumeFace, getFace } = useWebSocket();
+const { proxy } = getCurrentInstance() as any;
+
+const data = reactive<any>({
+  faceCheckStu: {},
+  faceState: false,//人脸识别窗口状态
+  direction: "",//动画方向
+  parameter: {},//参数
+});
+
+const { faceCheckStu, faceState, direction, parameter } = toRefs(data);
+
+onBeforeMount(() => {
+  //加载手势WS
+  faceWs((e: any) => {
+    if (e?.wksid) {
+      getCheckGrades();
+      openFace();
+    }
+  });
+})
+
+/**
+ * 查成绩
+*/
+const getCheckGrades = () => {
+  const deviceid: any = localStorage.getItem('deviceid');
+  if (!deviceid) {
+    proxy?.$modal.msgWarning('没有设备号,请重新登录');
+    return false;
+  }
+  checkFace()
+};
+
+
+</script>
+<style lang="scss" scoped>
+.mask {
+  position: fixed;
+  height: 100vh;
+  width: 100vw;
+  top: 0;
+  left: 0;
+  background: rgba(0, 0, 0, 0.3);
+  z-index: 998;
+}
+
+.confirmDiaBg {
+  width: 100%;
+  height: 100vh;
+  position: fixed;
+  left: 0;
+  top: 0;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 999;
+
+  .confirmDiaWindow {
+    width: 23.5%;
+    height: 43.4%;
+    border-radius: 1.6rem;
+    opacity: 1;
+    background: radial-gradient(122% 126% at 97% 6%, #35FFC6 0%, #00FFE8 100%);
+    text-align: center;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    position: fixed;
+
+    .confirmDiaWindow-con {
+      .pic {
+        width: 22.3vh;
+        height: 22.3vh;
+        border-radius: 50%;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        overflow: hidden;
+        position: relative;
+        margin: 0 auto 2vh auto;
+
+        .shine {
+          position: absolute;
+          left: -5vh;
+          top: 0;
+          width: 5vh;
+          height: 22.3vh;
+          animation: shineani 3s infinite;
+          -webkit-animation: shineani 3s infinite;
+          z-index: 1;
+
+          img {
+            width: 100%;
+            height: 100%;
+          }
+        }
+
+        img {
+          width: 100%;
+        }
+      }
+
+      .pic2 {
+        box-sizing: border-box;
+        border: 0.44rem solid rgba(26, 41, 58, 0.6315);
+      }
+
+      .name {
+        width: 100%;
+        color: #1A293A;
+        font-size: 1.9rem;
+      }
+
+      .name2 {
+        padding: 0 0.3rem;
+        border-radius: 1.1rem;
+        background: radial-gradient(96% 96% at 2% 32%, #FFFFFF 0%, #FCFDFD 54%, #E1E4E7 100%);
+        box-shadow: inset 0px 1px 0px 2px rgba(255, 255, 255, 0.9046), inset 0px 3px 6px 0px rgba(0, 0, 0, 0.0851);
+      }
+    }
+  }
+}
+
+@keyframes shineani {
+  0% {
+    left: -5vh;
+  }
+
+  100% {
+    left: calc(22.3vh + 5vh);
+  }
+}
+</style>

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

@@ -8,6 +8,7 @@ export {}
 declare module 'vue' {
   export interface GlobalComponents {
     ChooseStudent: typeof import('./../components/ChooseStudent/index.vue')['default']
+    copy: typeof import('./../components/FaceWindow copy/index.vue')['default']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
     ElButton: typeof import('element-plus/es')['ElButton']
     ElIcon: typeof import('element-plus/es')['ElIcon']
@@ -23,6 +24,7 @@ declare module 'vue' {
     JumpRopeGame: typeof import('./../components/JumpRopeGame/index.vue')['default']
     MultipleItem: typeof import('./../components/MultipleItem/index.vue')['default']
     MultipleItemRanking: typeof import('./../components/MultipleItemRanking/index.vue')['default']
+    OnlineFaceWindow: typeof import('./../components/OnlineFaceWindow/index.vue')['default']
     OptionWindow: typeof import('./../components/OptionWindow/index.vue')['default']
     RankingWindow: typeof import('./../components/RankingWindow/index.vue')['default']
     ReportList: typeof import('./../components/ReportList/index.vue')['default']

+ 143 - 0
src/utils/faceWs.ts

@@ -0,0 +1,143 @@
+import io from 'socket.io-client';
+import { ref, onMounted, onUnmounted, onBeforeUnmount } from 'vue';
+
+export function useWebSocket() {
+  const address: any = import.meta.env.VITE_APP_BASE_API;
+  const token: any = localStorage.getItem('token');
+  const deviceid: any = localStorage.getItem('deviceid');
+  const myToken: any = 'JWT ' + token;
+  const ctrlName: any = `facecontroller_${deviceid}`
+
+  let socketFace: any = null; //ws实例对象
+  socketFace = io(address + '/', {
+    transports: ['websocket', 'polling'],
+    query: {
+      type: 'face',
+      Authorization: token ? myToken : ''
+    }
+  });
+
+  function faceWs(callback: any) {
+    if (socketFace == null) {
+      return false;
+    }
+    callback({
+      wksid: socketFace.id
+    });
+    socketFace.on('my_response', (e: any) => {
+      callback(e);
+    });
+    socketFace.on('facecontroller_ack', (e: any) => {
+      callback(e);
+    });
+    socketFace.on('disconnect', (e: any) => {
+      callback(e);
+    });
+  }
+
+  /**
+   * 发送消息
+   */
+  function sendMessage(type: string, data: any, callback?: () => void) {
+    if (socketFace == null) {
+      return false;
+    }
+    if (socketFace.connected) {
+      callback = callback || function () {};
+      socketFace.emit(type, data, callback);
+    }
+  }
+
+  /**
+   * 查看人脸识别模块是否可用
+   */
+  function checkFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'check_facecontroller_available',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  /**
+   * 开启人脸识别模块
+   */
+  function openFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'open_facecontroller',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  /**
+   * 关闭人脸识别模块
+   */
+  function terminateFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'terminate_facecontroller',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  /**
+   * 暂停人脸识别模块
+   */
+  function suspendFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'suspend_facecontroller',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  /**
+   * 重启人脸识别模块
+   */
+  function resumeFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'resume_facecontroller',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  /**
+   * 获取人脸识别模块状态
+   */
+  function getFace(data?: any, callback?: any) {
+    sendMessage(
+      'facecontroller_ack',
+      {
+        cmd: 'get_facecontroller_state',
+        ctrl_name: ctrlName,
+      },
+      () => {}
+    );
+  }
+
+  onBeforeUnmount(() => {
+    if (socketFace) {
+      socketFace.close();
+      socketFace = null;
+    }
+  });
+
+  return { faceWs, sendMessage, checkFace, openFace, terminateFace, suspendFace, resumeFace, getFace };
+}

+ 15 - 0
src/views/set/index.vue

@@ -47,6 +47,14 @@
           </div>
         </div>
       </div>
+      <div class="li" @click="getCheckGrades">
+        <div class="liBox">
+          <div class="pic"></div>
+          <div class="name">
+            测试查成绩
+          </div>
+        </div>
+      </div>
       <div class="li" @click="getLogout">
         <div class="liBox">
           <div class="pic"><img src="@/assets/images/common/set2.png"></div>
@@ -64,6 +72,7 @@
         </div>
       </div> -->
     </div>
+    <OnlineFaceWindow></OnlineFaceWindow>
   </div>
 </template>
 
@@ -220,6 +229,12 @@ const getText = (type: any) => {
   }
 };
 
+/**
+ * 查成绩
+*/
+const getCheckGrades = () => {
+
+};
 
 /**
  * 返回