|
|
@@ -2,45 +2,174 @@
|
|
|
<div class="face-recognition">
|
|
|
<!-- 顶部导航 -->
|
|
|
<van-nav-bar title="自然人开票" fixed placeholder />
|
|
|
+
|
|
|
+ <!-- 步骤卡片 -->
|
|
|
<div class="card">
|
|
|
<StepProgress :activeStep="2" />
|
|
|
</div>
|
|
|
+
|
|
|
+ <!-- iframe 容器 -->
|
|
|
+ <div class="iframe-page">
|
|
|
+ <iframe
|
|
|
+ :src="etsUrl"
|
|
|
+ frameborder="0"
|
|
|
+ class="iframe"
|
|
|
+ allowfullscreen
|
|
|
+ scrolling="no"
|
|
|
+ ref="iframeRef"
|
|
|
+ ></iframe>
|
|
|
+ </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup lang="ts">
|
|
|
import StepProgress from '@/components/StepProgress.vue'
|
|
|
-import { getFaceAuthInfoApi } from '@/services/modules/faceRecognition'
|
|
|
-import { onBeforeMount } from 'vue'
|
|
|
+import { getFaceAuthInfoApi, getFaceAuthResultApi } from '@/services/modules/faceRecognition'
|
|
|
+import { ref, onBeforeMount, onMounted, onUnmounted } from 'vue'
|
|
|
+import { showToast } from 'vant'
|
|
|
+import { useRouter } from 'vue-router'
|
|
|
+const router = useRouter()
|
|
|
|
|
|
+const etsUrl = ref('')
|
|
|
+
|
|
|
+// 获取认证链接
|
|
|
const getConfirmInvoiceInfo = async () => {
|
|
|
const res = await getFaceAuthInfoApi()
|
|
|
- console.log('res', res)
|
|
|
+ if (res.code === 0 && res.data?.faceAuthUrl) {
|
|
|
+ etsUrl.value = res.data.faceAuthUrl
|
|
|
+ } else {
|
|
|
+ console.warn('获取认证链接失败', res)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 获取认证结果
|
|
|
+const getFaceAuthResult = async () => {
|
|
|
+ try {
|
|
|
+ const res = await getFaceAuthResultApi()
|
|
|
+
|
|
|
+ if (res.code === 0 && res.data?.success) {
|
|
|
+ showToast('认证成功,跳转下一步')
|
|
|
+
|
|
|
+ // ✅ 设置一次性标记(给下个页面用)
|
|
|
+ sessionStorage.setItem('FACE_AUTH_DONE', '1')
|
|
|
+
|
|
|
+ // ✅ 使用 replace 替换当前路由,不留返回记录
|
|
|
+ setTimeout(() => {
|
|
|
+ router.replace({
|
|
|
+ path: '/invoice-information',
|
|
|
+ })
|
|
|
+ }, 800)
|
|
|
+ } else {
|
|
|
+ showToast('认证失败,请刷新页面后重试')
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ console.error('获取认证结果失败', err)
|
|
|
+ showToast('网络错误,请稍后重试')
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+// 🧠 监听 iframe 发来的消息
|
|
|
+const handleMessage = (event: MessageEvent) => {
|
|
|
+ // 忽略 React DevTools 的心跳消息
|
|
|
+ if (event.data?.source === 'react-devtools-content-script') return
|
|
|
+
|
|
|
+ console.log('📩 收到 iframe 消息:', event.data)
|
|
|
+
|
|
|
+ if (event.data?.type === 'AUTH_DONE') {
|
|
|
+ showToast('认证完成,跳转下一步')
|
|
|
+ // 比如继续执行下一步逻辑
|
|
|
+ } else if (event.data?.type === 'AUTH_ERROR') {
|
|
|
+ showToast('认证失败:' + event.data.message)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+onMounted(() => {
|
|
|
+ window.addEventListener('message', handleMessage)
|
|
|
+})
|
|
|
+
|
|
|
+onUnmounted(() => {
|
|
|
+ window.removeEventListener('message', handleMessage)
|
|
|
+})
|
|
|
+
|
|
|
onBeforeMount(() => {
|
|
|
getConfirmInvoiceInfo()
|
|
|
+
|
|
|
+ // 模拟获取认证结果
|
|
|
+ setTimeout(() => {
|
|
|
+ getFaceAuthResult()
|
|
|
+ }, 5000)
|
|
|
})
|
|
|
</script>
|
|
|
|
|
|
-<style lang="scss" scoped>
|
|
|
+<style scoped lang="scss">
|
|
|
.face-recognition {
|
|
|
+ height: 100dvh;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
background: #f5f6f8;
|
|
|
- min-height: 100vh;
|
|
|
font-family:
|
|
|
-apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Microsoft YaHei',
|
|
|
sans-serif;
|
|
|
font-size: 3.8vw;
|
|
|
padding: 4vw 3.5vw;
|
|
|
+ box-sizing: border-box;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
|
|
|
- .card {
|
|
|
- background: #fff;
|
|
|
- border-radius: 14px;
|
|
|
- margin-bottom: 5vw;
|
|
|
- padding: 4vw 3.5vw;
|
|
|
- box-shadow:
|
|
|
- 0 4px 12px rgba(0, 0, 0, 0.06),
|
|
|
- 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
|
- transition: all 0.3s ease;
|
|
|
- }
|
|
|
+/* 顶部步骤进度卡片 */
|
|
|
+.card {
|
|
|
+ background: #fff;
|
|
|
+ border-radius: 14px;
|
|
|
+ margin-bottom: 4vw;
|
|
|
+ padding: 4vw 3.5vw;
|
|
|
+ box-shadow:
|
|
|
+ 0 4px 12px rgba(0, 0, 0, 0.06),
|
|
|
+ 0 1px 3px rgba(0, 0, 0, 0.04);
|
|
|
+ flex-shrink: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* iframe 外层 */
|
|
|
+.iframe-page {
|
|
|
+ flex: 1;
|
|
|
+ min-height: 0;
|
|
|
+ overflow: hidden;
|
|
|
+ /* 用负边距抵消父 padding,使 iframe 全宽 */
|
|
|
+ margin-left: -3.5vw;
|
|
|
+ margin-right: -3.5vw;
|
|
|
+ margin-bottom: -4vw; /* 让底部贴合视口 */
|
|
|
+ border-radius: 0;
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
+
|
|
|
+/* iframe 内容 */
|
|
|
+.iframe {
|
|
|
+ position: absolute;
|
|
|
+ top: 0;
|
|
|
+ left: 0;
|
|
|
+ width: 100vw; /* 全屏宽 */
|
|
|
+ height: 100%;
|
|
|
+ border: none;
|
|
|
+ display: block;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ /* 禁止横向滚动条 */
|
|
|
+ overflow-x: hidden;
|
|
|
+ overflow-y: auto;
|
|
|
+ -webkit-overflow-scrolling: touch; /* 移动端平滑滚动 */
|
|
|
+}
|
|
|
+
|
|
|
+/* iframe 外层滚动条美化(仅当内部非跨域时生效) */
|
|
|
+.iframe::-webkit-scrollbar {
|
|
|
+ width: 6px;
|
|
|
+}
|
|
|
+.iframe::-webkit-scrollbar-thumb {
|
|
|
+ background: rgba(255, 122, 0, 0.4);
|
|
|
+ border-radius: 4px;
|
|
|
+}
|
|
|
+.iframe::-webkit-scrollbar-thumb:hover {
|
|
|
+ background: rgba(255, 122, 0, 0.7);
|
|
|
+}
|
|
|
+.iframe::-webkit-scrollbar-track {
|
|
|
+ background: transparent;
|
|
|
}
|
|
|
</style>
|