yuanmingze преди 2 седмици
родител
ревизия
1dfc800bf7
променени са 2 файла, в които са добавени 79 реда и са изтрити 17 реда
  1. 5 1
      src/services/modules/faceRecognition/index.ts
  2. 74 16
      src/views/pedding-face-recognition/index.vue

+ 5 - 1
src/services/modules/faceRecognition/index.ts

@@ -13,9 +13,13 @@ export const getFaceAuthInfoApi = (data: GetFaceAuthInfoRequest) => {
   })
 }
 
-export const getFaceAuthResultApi = (data: PushRecordIdRequest) => {
+export const getFaceAuthResultApi = (
+  data: PushRecordIdRequest,
+  options: { timeout?: number } = {},
+) => {
   return http.post<GetFaceAuthResultReqsponse>({
     url: '/admin/invoice-order/get-face-auth-result',
     data,
+    ...options,
   })
 }

+ 74 - 16
src/views/pedding-face-recognition/index.vue

@@ -55,7 +55,7 @@
 <script setup lang="ts">
 import { getFaceAuthResultApi } from '@/services/modules/faceRecognition'
 import type { PushRecordIdRequest } from '@/services/modules/invoiceInformation/type.d.ts'
-import { ref, reactive, onMounted } from 'vue'
+import { ref, reactive, onMounted, onBeforeUnmount } from 'vue'
 import { useUserStore } from '@/stores/modules/user'
 import { showToast } from 'vant'
 import { useInvoice } from '@/hooks/useInvoice'
@@ -75,36 +75,87 @@ const params = reactive<PushRecordIdRequest>({
 })
 
 const lowCertLevelDialog = ref(false)
-// 获取认证结果
-const getFaceAuthResult = async () => {
-  try {
-    const res = await getFaceAuthResultApi(params)
+const FACE_AUTH_POLL_INTERVAL = 1000
+const FACE_AUTH_POLL_TIMEOUT = 8000
+let pollTimer: ReturnType<typeof setTimeout> | undefined
+let timeoutTimer: ReturnType<typeof setTimeout> | undefined
+let redirectTimer: ReturnType<typeof setTimeout> | undefined
+let pollingStopped = false
+let pollingDeadline = 0
+let lastResponse: Awaited<ReturnType<typeof getFaceAuthResultApi>> | undefined
+
+const stopPolling = () => {
+  pollingStopped = true
+  clearTimeout(pollTimer)
+  clearTimeout(timeoutTimer)
+}
+
+// 轮询结束后,沿用原有的认证结果和异常处理。
+const handleFaceAuthResult = async () => {
+  if (pollingStopped) return
+  stopPolling()
 
-    if (res.code === 0 && res.data.lowCertLevel) {
+  const res = lastResponse
+  if (!res) {
+    showToast('网络错误,请稍后重试')
+  } else {
+    if (res.code === 0 && res.data?.lowCertLevel) {
       lowCertLevelDialog.value = true
       return
     }
 
     if (res.code === 0 && res.data?.success) {
-      const rzzt = res.data.rzzt
-      // 已认证或无需认证提交跳转
-      if (rzzt === 'NO_REQUIRED_AUTHENTICATION') {
-        submitInvoiceForce()
+      if (res.data.rzzt === 'NO_REQUIRED_AUTHENTICATION') {
+        await submitInvoiceForce()
         return
       }
     } else {
       showToast('扫脸认证失败,请重试')
     }
+  }
+
+  redirectTimer = setTimeout(() => {
+    router.replace('/invoice-information')
+  }, 1800)
+}
+
+// 串行轮询,接口耗时也计入 8 秒上限。
+const getFaceAuthResult = async () => {
+  if (pollingStopped) return
+
+  const remainingTime = pollingDeadline - Date.now()
+  if (remainingTime <= 0) {
+    await handleFaceAuthResult()
+    return
+  }
+
+  try {
+    const res = await getFaceAuthResultApi(params, { timeout: remainingTime })
+    // 超时或离开页面后,不再处理迟到的结果。
+    if (pollingStopped) return
+    if (Date.now() >= pollingDeadline) {
+      await handleFaceAuthResult()
+      return
+    }
+
+    lastResponse = res
+    // 只在出现目标状态时提前结束轮询,其他结果等到 8 秒后统一处理。
+    if (res.data?.rzzt === 'NO_REQUIRED_AUTHENTICATION') {
+      await handleFaceAuthResult()
+      return
+    }
   } catch (err) {
+    if (pollingStopped) return
+    lastResponse = undefined
     console.error('获取认证结果失败', err)
-    showToast('网络错误,请稍后重试')
   }
 
-  setTimeout(() => {
-    router.replace({
-      path: '/invoice-information',
-    })
-  }, 1800)
+  if (!pollingStopped) {
+    pollTimer = setTimeout(
+      getFaceAuthResult,
+      Math.min(FACE_AUTH_POLL_INTERVAL, Math.max(0, pollingDeadline - Date.now())),
+    )
+  }
 }
 
 const lowCertLevelConfirm = () => {
@@ -117,8 +168,15 @@ const handleSecurityLevelGuideClick = () => {
 }
 
 onMounted(() => {
+  pollingDeadline = Date.now() + FACE_AUTH_POLL_TIMEOUT
+  timeoutTimer = setTimeout(handleFaceAuthResult, FACE_AUTH_POLL_TIMEOUT)
   getFaceAuthResult()
 })
+
+onBeforeUnmount(() => {
+  stopPolling()
+  clearTimeout(redirectTimer)
+})
 </script>
 
 <style scoped>