Files
ks-app-employment-service/pages/login/id-card-login.vue

373 lines
7.7 KiB
Vue
Raw Normal View History

2025-11-14 18:10:59 +08:00
<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'
})
// 跳转到首页
2025-11-14 19:05:03 +08:00
// uni.reLaunch({
// url: '/pages/index/index'
// })
2025-11-14 18:10:59 +08:00
} 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) => {
// 处理第三方跳转过来的身份证登录
2025-11-14 19:05:03 +08:00
if (options.idCard) {
2025-11-14 18:10:59 +08:00
// 直接通过参数传递
2025-11-14 19:05:03 +08:00
processIdCardLogin(options.idCard)
2025-11-14 18:10:59 +08:00
} else {
// 从当前URL中获取参数
const currentPages = getCurrentPages()
const currentPage = currentPages[currentPages.length - 1]
const url = currentPage.$page.fullPath
const params = getUrlParams(url)
2025-11-14 19:05:03 +08:00
if (params.idCard) {
processIdCardLogin(params.idCard)
2025-11-14 18:10:59 +08:00
} else {
uni.showToast({
title: '缺少身份证号码参数',
icon: 'none'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
})
// 处理身份证登录流程
2025-11-14 19:05:03 +08:00
const processIdCardLogin = async (idCard) => {
2025-11-14 18:10:59 +08:00
try {
// 解码Base64身份证号码
2025-11-14 19:05:03 +08:00
const decodedIdCard = decodeBase64(idCard)
2025-11-14 18:10:59 +08:00
// 验证身份证号码格式(简单验证)
2025-11-14 19:05:03 +08:00
if (!decodedIdCard || decodedIdCard.length < 15) {
2025-11-14 18:10:59 +08:00
throw new Error('身份证号码格式不正确')
}
// 调用登录接口
2025-11-14 19:05:03 +08:00
await handleIdCardLogin(decodedIdCard)
2025-11-14 18:10:59 +08:00
} catch (error) {
console.error('处理身份证登录失败:', error)
uni.showToast({
title: error.message || '处理身份证信息失败',
icon: 'none'
})
setTimeout(() => {
uni.navigateBack()
}, 1500)
}
}
onMounted(() => {
// 页面挂载后的逻辑
2025-11-14 19:05:03 +08:00
// 这里可以添加页面挂载后的其他逻辑
2025-11-14 18:10:59 +08:00
})
</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>