Browse Source

✨ feat: 更新人脸采集功能

Pchen. 8 months ago
parent
commit
33657cb386
4 changed files with 74 additions and 24 deletions
  1. 1 1
      src/App.vue
  2. 3 3
      src/pages/face/components/doc.vue
  3. 27 8
      src/pages/face/components/faceReco.vue
  4. 43 12
      src/pages/face/index.vue

+ 1 - 1
src/App.vue

@@ -64,7 +64,7 @@ async function GetAppVersion() {
 }
 
 onMounted(() => {
-  checkMobile()
+  // checkMobile()
   GetAppVersion()
 })
 

+ 3 - 3
src/pages/face/components/doc.vue

@@ -1,6 +1,6 @@
 <template>
     <div style="text-align: left;">
-        <p style="text-indent: 2em;">为保障识别准确性与用户隐私,请在使用人脸识别功能前阅读并遵守下列须知。</p>
+        <p style="text-indent: 2em;">为保障识别准确性与用户隐私,请在使用人脸采集功能前阅读并遵守下列须知。</p>
 
         <h3>一、拍摄与画面要求</h3>
         <ol>
@@ -18,9 +18,9 @@
 
         <h3>三、数据使用范围与隐私承诺</h3>
         <ol>
-            <li>RunForge 仅在<strong>校园乐跑活动的人脸识别</strong>环节使用所采集的人脸数据,不作其他用途。</li>
+            <li>RunForge 仅在<strong>校园乐跑的人脸识别</strong>环节使用所采集的人脸数据,不作其他用途。</li>
             <li>所有人脸数据将被妥善保存与加密保护;未经数据主体的明确同意,RunForge 不会向第三方披露或挪用该类数据。</li>
-            <li>若需删除您的数据,请联系RunForge客服。</li>
+            <li>若需删除或更改您的数据,请联系RunForge客服。</li>
         </ol>
     </div>
 </template>

+ 27 - 8
src/pages/face/components/faceReco.vue

@@ -13,7 +13,6 @@
         </div>
       </div>
 
-
       <div class="faceInfo">
         <a-tag size="large" :color="tagColor">
           {{ tagInfo }}
@@ -26,12 +25,12 @@
       </div>
     </div>
 
-    <div v-if="step === 2">
+    <div v-if="step === 2" class="spin">
       <a-spin dot tip="人脸信息上传中,请稍候..." />
     </div>
 
-    <div class="success" v-if="step === 3">
-      <a-result status="success" title="识别完成">
+    <div v-if="step === 3">
+      <a-result status="success" title="采集完成">
         <template #extra>
           <a-space>
             <a-button type='primary' @click="$router.go(0)">返回</a-button>
@@ -40,6 +39,16 @@
       </a-result>
     </div>
 
+    <div v-if="step === 4">
+      <a-result status="error" title="采集失败">
+        <template #extra>
+          <a-space>
+            <a-button type='primary' @click="$router.go(0)">返回重试</a-button>
+          </a-space>
+        </template>
+      </a-result>
+    </div>
+
     <div class="userInfo">
       <div class="left">
         <a-avatar>
@@ -188,6 +197,7 @@ async function uploadVideo(blob) {
     step.value = 2
     const formData = new FormData()
     formData.append("student_num", props.userInfo.student_num)
+    formData.append("key", props.userInfo.key)
     formData.append("upload", blob, "face_record.webm")
 
     const url = import.meta.env.VITE_APP_API_BASE_URL + '/UploadFaceVideo'
@@ -196,13 +206,16 @@ async function uploadVideo(blob) {
       headers: { "Content-Type": "multipart/form-data" }
     })
 
-    if (!res || !res.data || res.data.code !== 0) throw new Error("上传失败")
+    if (!res || !res.data || res.data.code !== 0) {
+      step.value = 4
+      throw new Error(res?.data?.msg ?? '上传失败,请稍后再试')
+    }
     Message.success("人脸数据上传成功")
+    step.value = 3
   } catch (err) {
-    Message.error("人脸数据上传失败")
+    step.value = 4
+    Message.error(err.message ?? "人脸数据上传失败")
     console.error(err)
-  } finally {
-    step.value = 3
   }
 }
 
@@ -419,6 +432,12 @@ onUnmounted(() => {
   transform: scaleX(-1);
 }
 
+.spin {
+  display: flex;
+  align-items: center;
+  min-height: 270px;
+}
+
 .userInfo {
   display: flex;
   align-items: center;

+ 43 - 12
src/pages/face/index.vue

@@ -3,20 +3,25 @@
         <div class="card" v-if="step === 1">
             <div class="logo">
                 <img alt="RunForge" src="/logo.svg" height="40">
-                <span class="title">RunForge | 人脸录入</span>
+                <span class="title">RunForge | 人脸采集</span>
             </div>
 
             <input type="text" id="name" placeholder="姓名">
             <input type="text" id="student_num" placeholder="学号">
+            <input type="text" id="captcha" placeholder="验证码">
+            <div id="captchaImg" @click="getCaptcha()" title="点击更换验证码">
+                <img alt="点我重试" :src="ImageCaptcha" v-if="ImageCaptcha" />
+                <a-spin dot v-else />
+            </div>
 
             <a-button type="primary" shape="round" size="large" @click="getUserInfo"
-                :loading="buttonLoading">开始人脸识别</a-button>
+                :loading="buttonLoading">开始人脸采集</a-button>
         </div>
 
         <div class="card" v-else-if="step === 2">
             <div class="logo">
                 <img alt="RunForge" src="/logo.svg" height="40">
-                <span class="title">人脸识别注意事项</span>
+                <span class="title">人脸采集注意事项</span>
             </div>
             <Doc />
             <a-button type="primary" shape="round" size="large" @click="step = 3"
@@ -26,9 +31,9 @@
         <div class="card" v-else-if="step === 3">
             <div class="logo">
                 <img alt="RunForge" src="/logo.svg" height="40">
-                <span class="title">RunForge | 人脸识别</span>
+                <span class="title">RunForge | 人脸采集</span>
             </div>
-            <FaceReco :userInfo="userInfo"/>
+            <FaceReco :userInfo="userInfo" />
         </div>
     </div>
 </template>
@@ -37,6 +42,7 @@
 import { ref, reactive, onMounted } from 'vue'
 import { Message } from '@arco-design/web-vue'
 import { BeginFaceReco } from '@/api/lepao'
+import { getImageCaptcha } from '@/api/login'
 import Doc from './components/doc.vue'
 import FaceReco from './components/faceReco.vue'
 
@@ -44,17 +50,39 @@ const step = ref(1)
 const buttonLoading = ref(false)
 const userInfo = ref({})
 
+let CaptchaId = ref('')
+let ImageCaptcha = ref('')
+
+const getCaptcha = async () => {
+    try {
+        const res = await getImageCaptcha()
+        if (!res || res.code != 0)
+            return Message.error('获取图片验证码失败!' + res?.msg ?? '')
+        ImageCaptcha.value = res.data.img
+        CaptchaId.value = res.data.id
+    } catch (error) {
+        Message.error('获取图片验证码失败!')
+    }
+}
+
 const getUserInfo = async () => {
     try {
         buttonLoading.value = true
         const name = document.getElementById('name').value
         const student_num = document.getElementById('student_num').value
-        if (!name || !student_num)
-            return Message.error('请将姓名、学号填写完整')
+        const captchaEl = document.getElementById('captcha')
+        const captcha = captchaEl.value
+        if (!name || !student_num || !captcha)
+            return Message.error('请将信息填写完整')
+
+        const res = await BeginFaceReco({ name, student_num, captcha, id: CaptchaId.value })
+        if (!res || res.code !== 0) {
+            Message.error(res?.msg ?? '获取人脸识别信息失败!请稍后再试')
+            getCaptcha()
+            captchaEl.value = ''
+            return
+        }
 
-        const res = await BeginFaceReco({ name, student_num })
-        if (!res || res.code !== 0)
-            return Message.error(res?.msg ?? '获取人脸识别信息失败!请稍后再试')
         userInfo.value = res.data
         step.value = 2
     } catch (error) {
@@ -66,6 +94,9 @@ const getUserInfo = async () => {
 
 // 预加载模型
 
+onMounted(() => {
+    getCaptcha()
+})
 </script>
 
 <style lang="less" scoped>
@@ -128,13 +159,13 @@ const getUserInfo = async () => {
     }
 
     button {
-        padding: 10px 20px;
+        padding: 20px 20px;
         border: none;
         border-radius: 10px;
         background-color: #4A90E2;
         color: #fff;
         cursor: pointer;
-        margin-top: 10px;
+        margin-top: 20px;
     }
 }
 </style>