Files
ks-app-employment-service/pages/login/id-card-login.vue
2025-11-18 11:14:48 +08:00

376 lines
7.7 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="loading-container">
<!-- 背景装饰元素 -->
<view class="bg-decoration">
<view class="bg-circle bg-circle-1"></view>
<view class="bg-circle bg-circle-2"></view>
<view class="bg-circle bg-circle-3"></view>
</view>
<!-- Loading内容 -->
<view class="loading-content">
<!-- 图标区域 -->
<view class="icon-section">
<view class="icon-wrapper">
<uni-icons type="idcard-filled" size="80" color="#FFFFFF"></uni-icons>
</view>
</view>
<!-- Loading动画 -->
<view class="loading-animation">
<view class="spinner"></view>
</view>
<!-- 文字内容 -->
<view class="text-section">
<view class="loading-text">登录中请稍候...</view>
<view class="loading-subtext">正在验证您的社保卡信息</view>
</view>
<!-- 进度指示器 -->
<view class="progress-section">
<view class="progress-bar">
<view class="progress-fill"></view>
</view>
<view class="progress-text">验证中...</view>
</view>
</view>
<!-- 底部信息 -->
<view class="footer">
<view class="footer-text">© 2024 社保就业服务平台</view>
</view>
</view>
</template>
<script setup>
import { inject, onMounted } from 'vue'
import { onLoad } from '@dcloudio/uni-app'
import useUserStore from '@/stores/useUserStore'
const { $api } = inject("globalFunction")
const userStore = useUserStore()
// 处理身份证号码登录
const handleIdCardLogin = async (idCard) => {
try {
// 调用身份证号码登录接口
const res = await $api.createRequest('/app/idCardLogin', {
idCard: idCard
}, 'post')
if (res.token) {
// 登录成功存储token并获取用户信息
await userStore.loginSetToken(res.token)
// 获取用户详细信息
await userStore.getUserResume()
uni.showToast({
title: '登录成功',
icon: 'success'
})
setTimeout(() => {
// 跳转到首页
uni.reLaunch({
url: '/pages/index/index'
})
}, 1500)
} else {
uni.showToast({
title: '登录失败',
icon: 'none'
})
// 登录失败,返回登录页面
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
} catch (error) {
console.error('身份证登录失败:', error)
uni.showToast({
title: error.msg || '登录失败,请重试',
icon: 'none'
})
// 登录失败,返回登录页面
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
// Base64解码
const decodeBase64 = (base64Str) => {
try {
// 在H5环境中使用atob解码
// #ifdef H5
return atob(base64Str)
// #endif
// 在小程序环境中使用uni.base64ToArrayBuffer
// #ifdef MP-WEIXIN
const arrayBuffer = uni.base64ToArrayBuffer(base64Str)
const uint8Array = new Uint8Array(arrayBuffer)
let result = ''
for (let i = 0; i < uint8Array.length; i++) {
result += String.fromCharCode(uint8Array[i])
}
return result
// #endif
// 在App环境中
// #ifdef APP-PLUS
return plus.base64.decode(base64Str)
// #endif
} catch (error) {
console.error('Base64解码失败:', error)
throw new Error('身份证号码解码失败')
}
}
// 解析URL参数
const getUrlParams = (url) => {
const params = {}
const urlObj = new URL(url)
const searchParams = new URLSearchParams(urlObj.search)
for (const [key, value] of searchParams) {
params[key] = value
}
return params
}
onLoad((options) => {
// 处理第三方跳转过来的身份证登录
if (options.idCard) {
// 直接通过参数传递
processIdCardLogin(options.idCard)
} else {
// 从当前URL中获取参数
const currentPages = getCurrentPages()
const currentPage = currentPages[currentPages.length - 1]
const url = currentPage.$page.fullPath
const params = getUrlParams(url)
if (params.idCard) {
processIdCardLogin(params.idCard)
} else {
uni.showToast({
title: '缺少身份证号码参数',
icon: 'none'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
})
// 处理身份证登录流程
const processIdCardLogin = async (idCard) => {
try {
// 解码Base64身份证号码
const decodedIdCard = decodeBase64(idCard)
// 验证身份证号码格式(简单验证)
if (!decodedIdCard || decodedIdCard.length < 15) {
throw new Error('身份证号码格式不正确')
return;
}
// 调用登录接口
await handleIdCardLogin(decodedIdCard)
} catch (error) {
console.error('处理身份证登录失败:', error)
uni.showToast({
title: error.message || '处理身份证信息失败',
icon: 'none'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
onMounted(() => {
// 页面挂载后的逻辑
// 这里可以添加页面挂载后的其他逻辑
})
</script>
<style lang="stylus" scoped>
.loading-container
padding: 0 40rpx
min-height: 100vh
background: linear-gradient(135deg, #4778EC 0%, #256BFA 100%)
position: relative
overflow: hidden
display: flex
flex-direction: column
justify-content: center
align-items: center
.bg-decoration
position: absolute
top: 0
left: 0
width: 100%
height: 100%
pointer-events: none
z-index: 1
.bg-circle
position: absolute
border-radius: 50%
background: rgba(255, 255, 255, 0.1)
.bg-circle-1
width: 400rpx
height: 400rpx
top: -200rpx
right: -100rpx
.bg-circle-2
width: 300rpx
height: 300rpx
bottom: 100rpx
left: -150rpx
.bg-circle-3
width: 200rpx
height: 200rpx
bottom: -50rpx
right: 100rpx
.loading-content
position: relative
z-index: 2
text-align: center
color: #FFFFFF
width: 100%
max-width: 600rpx
.icon-section
margin-bottom: 60rpx
.icon-wrapper
display: inline-flex
align-items: center
justify-content: center
width: 160rpx
height: 160rpx
background: rgba(255, 255, 255, 0.2)
border-radius: 50%
backdrop-filter: blur(10rpx)
border: 2rpx solid rgba(255, 255, 255, 0.3)
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.2)
.loading-animation
margin-bottom: 60rpx
.spinner
width: 80rpx
height: 80rpx
margin: 0 auto
border: 6rpx solid rgba(255, 255, 255, 0.3)
border-radius: 50%
border-top: 6rpx solid #FFFFFF
animation: spin 1s linear infinite
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.2)
.text-section
margin-bottom: 60rpx
.loading-text
font-size: 40rpx
font-weight: 700
margin-bottom: 20rpx
text-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2)
.loading-subtext
font-size: 30rpx
opacity: 0.9
font-weight: 500
.progress-section
.progress-bar
width: 100%
height: 8rpx
background: rgba(255, 255, 255, 0.3)
border-radius: 4rpx
overflow: hidden
margin-bottom: 20rpx
.progress-fill
width: 60%
height: 100%
background: linear-gradient(90deg, #FFFFFF 0%, rgba(255, 255, 255, 0.8) 100%)
border-radius: 4rpx
animation: progress 2s ease-in-out infinite alternate
.progress-text
font-size: 26rpx
opacity: 0.8
font-weight: 500
.footer
position: absolute
bottom: 40rpx
left: 0
right: 0
text-align: center
z-index: 2
.footer-text
font-size: 24rpx
color: rgba(255, 255, 255, 0.7)
// 动画定义
@keyframes spin
0%
transform: rotate(0deg)
100%
transform: rotate(360deg)
@keyframes progress
0%
width: 30%
transform: translateX(-100%)
50%
width: 60%
100%
width: 30%
transform: translateX(233%)
// 响应式设计
@media (max-width: 750px)
.loading-container
padding: 0 32rpx
.loading-content
max-width: 500rpx
.icon-section
margin-bottom: 40rpx
.icon-wrapper
width: 120rpx
height: 120rpx
.loading-animation
margin-bottom: 40rpx
.text-section
margin-bottom: 40rpx
.loading-text
font-size: 36rpx
.loading-subtext
font-size: 28rpx
.progress-section
.progress-text
font-size: 24rpx
</style>