|
@@ -55,7 +55,7 @@
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
import { getFaceAuthResultApi } from '@/services/modules/faceRecognition'
|
|
import { getFaceAuthResultApi } from '@/services/modules/faceRecognition'
|
|
|
import type { PushRecordIdRequest } from '@/services/modules/invoiceInformation/type.d.ts'
|
|
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 { useUserStore } from '@/stores/modules/user'
|
|
|
import { showToast } from 'vant'
|
|
import { showToast } from 'vant'
|
|
|
import { useInvoice } from '@/hooks/useInvoice'
|
|
import { useInvoice } from '@/hooks/useInvoice'
|
|
@@ -75,36 +75,87 @@ const params = reactive<PushRecordIdRequest>({
|
|
|
})
|
|
})
|
|
|
|
|
|
|
|
const lowCertLevelDialog = ref(false)
|
|
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
|
|
lowCertLevelDialog.value = true
|
|
|
return
|
|
return
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (res.code === 0 && res.data?.success) {
|
|
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
|
|
return
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
showToast('扫脸认证失败,请重试')
|
|
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) {
|
|
} catch (err) {
|
|
|
|
|
+ if (pollingStopped) return
|
|
|
|
|
+ lastResponse = undefined
|
|
|
console.error('获取认证结果失败', err)
|
|
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 = () => {
|
|
const lowCertLevelConfirm = () => {
|
|
@@ -117,8 +168,15 @@ const handleSecurityLevelGuideClick = () => {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
onMounted(() => {
|
|
|
|
|
+ pollingDeadline = Date.now() + FACE_AUTH_POLL_TIMEOUT
|
|
|
|
|
+ timeoutTimer = setTimeout(handleFaceAuthResult, FACE_AUTH_POLL_TIMEOUT)
|
|
|
getFaceAuthResult()
|
|
getFaceAuthResult()
|
|
|
})
|
|
})
|
|
|
|
|
+
|
|
|
|
|
+onBeforeUnmount(() => {
|
|
|
|
|
+ stopPolling()
|
|
|
|
|
+ clearTimeout(redirectTimer)
|
|
|
|
|
+})
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|
|
|
<style scoped>
|
|
<style scoped>
|