一体机登录功能开发
This commit is contained in:
@@ -425,6 +425,7 @@ const { $api, navTo, vacanciesTo, formatTotal, config } = inject('globalFunction
|
||||
import { onLoad, onShow } from '@dcloudio/uni-app';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import useUserStore from '@/stores/useUserStore';
|
||||
import { checkLoginAndNavigate, getPlatformType } from '@/utils/loginHelper';
|
||||
const { userInfo, hasLogin, token } = storeToRefs(useUserStore());
|
||||
|
||||
// 计算是否显示求职者内容
|
||||
@@ -685,8 +686,8 @@ watch([hasLogin, userInfo], () => {
|
||||
const checkLogin = () => {
|
||||
const tokenValue = uni.getStorageSync('token') || '';
|
||||
if (!tokenValue || !hasLogin.value) {
|
||||
// 未登录,打开授权弹窗
|
||||
wxAuthLoginRef.value?.open();
|
||||
// 未登录,根据平台类型跳转到对应登录页面
|
||||
checkLoginAndNavigate();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
v-model="formData.jobLocation"
|
||||
/>
|
||||
<view class="location-icon-btn" @click="chooseLocation">
|
||||
<uni-icons type="location" size="20" color="#256BFA"></uni-icons>
|
||||
<uni-icons type="location" size="20" color="#333"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -800,25 +800,27 @@ const validateForm = () => {
|
||||
|
||||
.location-input {
|
||||
flex: 1;
|
||||
padding-right: 80rpx;
|
||||
padding-right: 100rpx;
|
||||
}
|
||||
|
||||
.location-icon-btn {
|
||||
position: absolute;
|
||||
right: -3px;
|
||||
top: 20%;
|
||||
transform: translateY(-50%);
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 8rpx;
|
||||
z-index: 99;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 44%;
|
||||
transform: translateY(-50%);
|
||||
width: 80rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f0f0f0;
|
||||
border: none;
|
||||
border-radius: 12rpx;
|
||||
transition: all 0.3s ease;
|
||||
z-index: 99;
|
||||
|
||||
&:active {
|
||||
background: #f0f0f0;
|
||||
transform: translateY(-50%) scale(0.95);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
529
pages/login/h5-login.vue
Normal file
529
pages/login/h5-login.vue
Normal file
@@ -0,0 +1,529 @@
|
||||
<template>
|
||||
<view class="login-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>
|
||||
|
||||
<!-- Logo和标题 -->
|
||||
<view class="login-header">
|
||||
<view class="logo-wrapper">
|
||||
<image class="logo" src="@/static/logo3.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="welcome-section">
|
||||
<view class="welcome-title">欢迎登录</view>
|
||||
<view class="welcome-subtitle">社保就业服务平台</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="login-form">
|
||||
<!-- 账号输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">账号</view>
|
||||
<view class="input-item">
|
||||
<uni-icons type="person-filled" size="28" color="#4778EC"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入手机号码"
|
||||
placeholder-class="placeholder"
|
||||
v-model="form.username"
|
||||
type="text"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 密码输入 -->
|
||||
<view class="input-group">
|
||||
<view class="input-label">密码</view>
|
||||
<view class="input-item">
|
||||
<uni-icons type="locked-filled" size="28" color="#4778EC"></uni-icons>
|
||||
<input
|
||||
class="input"
|
||||
placeholder="请输入您的密码"
|
||||
placeholder-class="placeholder"
|
||||
v-model="form.password"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
/>
|
||||
<view class="password-toggle" @click="togglePasswordVisibility">
|
||||
<uni-icons :type="showPassword ? 'eye-slash-filled' : 'eye-filled'" size="28" color="#999"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 密码规则提示 -->
|
||||
<view class="password-rules">
|
||||
<view class="rule-item" :class="{ 'rule-valid': validateRule('length') }">
|
||||
<uni-icons :type="validateRule('length') ? 'checkmarkempty' : 'circle'" size="20" :color="validateRule('length') ? '#52c41a' : '#999'"></uni-icons>
|
||||
<text class="rule-text">长度8位</text>
|
||||
</view>
|
||||
<view class="rule-item" :class="{ 'rule-valid': validateRule('letterNumber') }">
|
||||
<uni-icons :type="validateRule('letterNumber') ? 'checkmarkempty' : 'circle'" size="20" :color="validateRule('letterNumber') ? '#52c41a' : '#999'"></uni-icons>
|
||||
<text class="rule-text">字母数字组合</text>
|
||||
</view>
|
||||
<view class="rule-item" :class="{ 'rule-valid': validateRule('upperLower') }">
|
||||
<uni-icons :type="validateRule('upperLower') ? 'checkmarkempty' : 'circle'" size="20" :color="validateRule('upperLower') ? '#52c41a' : '#999'"></uni-icons>
|
||||
<text class="rule-text">大小写字母</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button class="login-btn" :class="{ 'login-btn-loading': loading }" @click="handleLogin">
|
||||
<view class="btn-content">
|
||||
<view class="btn-text" v-if="!loading">登录</view>
|
||||
<view class="loading-spinner" v-else></view>
|
||||
</view>
|
||||
</button>
|
||||
|
||||
<!-- 其他登录方式 -->
|
||||
<view class="other-login">
|
||||
<view class="divider">
|
||||
<view class="divider-line"></view>
|
||||
<view class="divider-text">其他登录方式</view>
|
||||
<view class="divider-line"></view>
|
||||
</view>
|
||||
|
||||
<view class="login-options">
|
||||
<view class="login-option" @click="goToIdCardLogin">
|
||||
<view class="option-icon">
|
||||
<uni-icons type="idcard" size="36" color="#4778EC"></uni-icons>
|
||||
</view>
|
||||
<view class="option-text">社保卡登录</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部信息 -->
|
||||
<view class="footer">
|
||||
<view class="footer-text">© 2024 社保就业服务平台</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, inject, ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import useUserStore from '@/stores/useUserStore'
|
||||
|
||||
const { $api } = inject("globalFunction")
|
||||
const userStore = useUserStore()
|
||||
|
||||
const form = reactive({
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const loading = ref(false)
|
||||
const showPassword = ref(false)
|
||||
|
||||
// 切换密码可见性
|
||||
const togglePasswordVisibility = () => {
|
||||
showPassword.value = !showPassword.value
|
||||
}
|
||||
|
||||
// 验证单个密码规则
|
||||
const validateRule = (ruleType) => {
|
||||
const password = form.password
|
||||
if (!password) return false
|
||||
|
||||
switch (ruleType) {
|
||||
case 'length':
|
||||
return password.length === 8
|
||||
case 'letterNumber':
|
||||
return /[a-zA-Z]/.test(password) && /\d/.test(password)
|
||||
case 'upperLower':
|
||||
return /[A-Z]/.test(password) && /[a-z]/.test(password)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 验证密码规则
|
||||
const validatePassword = (password) => {
|
||||
// 规则1: 必须有字母数字组合
|
||||
const hasLetterAndNumber = /[a-zA-Z]/.test(password) && /\d/.test(password)
|
||||
|
||||
// 规则2: 至少一个大写和一个小写字母
|
||||
const hasUpperCase = /[A-Z]/.test(password)
|
||||
const hasLowerCase = /[a-z]/.test(password)
|
||||
|
||||
// 规则3: 长度必须是8位
|
||||
const isLength8 = password.length === 8
|
||||
|
||||
if (!hasLetterAndNumber) {
|
||||
return '密码必须包含字母和数字组合'
|
||||
}
|
||||
if (!hasUpperCase) {
|
||||
return '密码必须包含至少一个大写字母'
|
||||
}
|
||||
if (!hasLowerCase) {
|
||||
return '密码必须包含至少一个小写字母'
|
||||
}
|
||||
if (!isLength8) {
|
||||
return '密码长度必须为8位'
|
||||
}
|
||||
|
||||
return null // 验证通过
|
||||
}
|
||||
|
||||
// 处理登录
|
||||
const handleLogin = async () => {
|
||||
if (!form.username) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入账号'
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!form.password) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: '请输入密码'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码规则
|
||||
const passwordError = validatePassword(form.password)
|
||||
if (passwordError) {
|
||||
uni.showToast({
|
||||
icon: 'none',
|
||||
title: passwordError
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
loading.value = true
|
||||
|
||||
try {
|
||||
// 调用账号密码登录接口
|
||||
const res = await $api.createRequest('/app/login', {
|
||||
username: form.username,
|
||||
password: form.password
|
||||
}, 'post')
|
||||
|
||||
if (res.token) {
|
||||
// 登录成功,存储token并获取用户信息
|
||||
await userStore.loginSetToken(res.token)
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
// 跳转到首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '登录失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
uni.showToast({
|
||||
title: error.msg || '登录失败,请重试',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 跳转到身份证号码登录页面
|
||||
const goToIdCardLogin = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/login/id-card-login'
|
||||
})
|
||||
}
|
||||
|
||||
onLoad(() => {
|
||||
// 页面加载时的初始化逻辑
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
.login-container
|
||||
padding: 0 40rpx
|
||||
min-height: 100vh
|
||||
background: linear-gradient(135deg, #4778EC 0%, #256BFA 100%)
|
||||
position: relative
|
||||
overflow: hidden
|
||||
|
||||
.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
|
||||
|
||||
.login-header
|
||||
position: relative
|
||||
z-index: 2
|
||||
text-align: center
|
||||
margin-bottom: 80rpx
|
||||
padding-top: 120rpx
|
||||
|
||||
.logo-wrapper
|
||||
margin-bottom: 40rpx
|
||||
|
||||
.logo
|
||||
width: 441rpx
|
||||
height: 160rpx
|
||||
filter: drop-shadow(0 8rpx 20rpx rgba(0, 0, 0, 0.2))
|
||||
|
||||
.welcome-section
|
||||
.welcome-title
|
||||
font-size: 48rpx
|
||||
font-weight: 700
|
||||
color: #FFFFFF
|
||||
margin-bottom: 16rpx
|
||||
text-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.2)
|
||||
|
||||
.welcome-subtitle
|
||||
font-size: 32rpx
|
||||
color: rgba(255, 255, 255, 0.9)
|
||||
font-weight: 500
|
||||
|
||||
.login-form
|
||||
position: relative
|
||||
z-index: 2
|
||||
background: #FFFFFF
|
||||
border-radius: 32rpx
|
||||
padding: 60rpx 40rpx
|
||||
box-shadow: 0 20rpx 60rpx rgba(0, 0, 0, 0.15)
|
||||
backdrop-filter: blur(20rpx)
|
||||
border: 1rpx solid rgba(255, 255, 255, 0.2)
|
||||
|
||||
.input-group
|
||||
margin-bottom: 48rpx
|
||||
|
||||
.input-label
|
||||
font-size: 28rpx
|
||||
font-weight: 600
|
||||
color: #333333
|
||||
margin-bottom: 20rpx
|
||||
padding-left: 10rpx
|
||||
|
||||
.input-item
|
||||
display: flex
|
||||
align-items: center
|
||||
padding: 0 32rpx
|
||||
height: 100rpx
|
||||
background: #F8F9FF
|
||||
border-radius: 25rpx
|
||||
border: 2rpx solid #E8ECFF
|
||||
transition: all 0.3s ease
|
||||
|
||||
&:focus-within
|
||||
border-color: #4778EC
|
||||
background: #FFFFFF
|
||||
box-shadow: 0 8rpx 24rpx rgba(71, 120, 236, 0.15)
|
||||
transform: translateY(-2rpx)
|
||||
|
||||
.input
|
||||
flex: 1
|
||||
height: 100%
|
||||
margin-left: 24rpx
|
||||
font-size: 32rpx
|
||||
color: #333333
|
||||
background: transparent
|
||||
font-weight: 500
|
||||
|
||||
.password-toggle
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
width: 60rpx
|
||||
height: 60rpx
|
||||
border-radius: 50%
|
||||
transition: all 0.3s ease
|
||||
cursor: pointer
|
||||
|
||||
&:active
|
||||
background: rgba(71, 120, 236, 0.1)
|
||||
transform: scale(0.9)
|
||||
|
||||
.placeholder
|
||||
font-size: 32rpx
|
||||
color: #999999
|
||||
font-weight: 400
|
||||
|
||||
.password-rules
|
||||
margin-top: 20rpx
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
gap: 20rpx
|
||||
|
||||
.rule-item
|
||||
display: flex
|
||||
align-items: center
|
||||
font-size: 24rpx
|
||||
color: #999999
|
||||
transition: all 0.3s ease
|
||||
|
||||
&.rule-valid
|
||||
color: #52c41a
|
||||
|
||||
.rule-text
|
||||
margin-left: 8rpx
|
||||
font-size: 24rpx
|
||||
|
||||
.login-btn
|
||||
width: 100%
|
||||
height: 100rpx
|
||||
background: linear-gradient(135deg, #4778EC 0%, #256BFA 100%)
|
||||
border-radius: 25rpx
|
||||
color: #FFFFFF
|
||||
font-size: 34rpx
|
||||
font-weight: 600
|
||||
border: none
|
||||
margin-bottom: 48rpx
|
||||
box-shadow: 0 12rpx 30rpx rgba(37, 107, 250, 0.4)
|
||||
transition: all 0.3s ease
|
||||
position: relative
|
||||
overflow: hidden
|
||||
|
||||
&:active
|
||||
transform: translateY(2rpx)
|
||||
box-shadow: 0 6rpx 20rpx rgba(37, 107, 250, 0.3)
|
||||
|
||||
&.login-btn-loading
|
||||
background: linear-gradient(135deg, #4778EC 0%, #256BFA 100%)
|
||||
opacity: 0.8
|
||||
|
||||
.btn-content
|
||||
display: flex
|
||||
align-items: center
|
||||
justify-content: center
|
||||
height: 100%
|
||||
|
||||
.btn-text
|
||||
font-size: 34rpx
|
||||
font-weight: 600
|
||||
|
||||
.loading-spinner
|
||||
width: 40rpx
|
||||
height: 40rpx
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3)
|
||||
border-radius: 50%
|
||||
border-top: 4rpx solid #FFFFFF
|
||||
animation: spin 1s linear infinite
|
||||
|
||||
.other-login
|
||||
.divider
|
||||
display: flex
|
||||
align-items: center
|
||||
margin-bottom: 40rpx
|
||||
|
||||
.divider-line
|
||||
flex: 1
|
||||
height: 1rpx
|
||||
background: #E5E5E5
|
||||
|
||||
.divider-text
|
||||
padding: 0 24rpx
|
||||
font-size: 26rpx
|
||||
color: #999999
|
||||
font-weight: 500
|
||||
|
||||
.login-options
|
||||
display: flex
|
||||
justify-content: center
|
||||
|
||||
.login-option
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
padding: 20rpx 40rpx
|
||||
border-radius: 20rpx
|
||||
background: #F8F9FF
|
||||
border: 2rpx solid #E8ECFF
|
||||
transition: all 0.3s ease
|
||||
cursor: pointer
|
||||
|
||||
&:active
|
||||
background: #F0F4FF
|
||||
transform: scale(0.95)
|
||||
|
||||
.option-icon
|
||||
margin-bottom: 16rpx
|
||||
|
||||
.option-text
|
||||
font-size: 24rpx
|
||||
color: #4778EC
|
||||
font-weight: 500
|
||||
|
||||
.footer
|
||||
position: relative
|
||||
z-index: 2
|
||||
text-align: center
|
||||
margin-top: 60rpx
|
||||
padding-bottom: 40rpx
|
||||
|
||||
.footer-text
|
||||
font-size: 24rpx
|
||||
color: rgba(255, 255, 255, 0.7)
|
||||
|
||||
// 按钮重置样式
|
||||
button::after
|
||||
border: none
|
||||
|
||||
// 动画定义
|
||||
@keyframes spin
|
||||
0%
|
||||
transform: rotate(0deg)
|
||||
100%
|
||||
transform: rotate(360deg)
|
||||
|
||||
// 响应式设计
|
||||
@media (max-width: 750px)
|
||||
.login-container
|
||||
padding: 0 32rpx
|
||||
|
||||
.login-header
|
||||
padding-top: 80rpx
|
||||
margin-bottom: 60rpx
|
||||
|
||||
.logo
|
||||
width: 360rpx
|
||||
height: 130rpx
|
||||
|
||||
.welcome-title
|
||||
font-size: 40rpx
|
||||
|
||||
.welcome-subtitle
|
||||
font-size: 28rpx
|
||||
|
||||
.login-form
|
||||
padding: 48rpx 32rpx
|
||||
border-radius: 24rpx
|
||||
</style>
|
||||
372
pages/login/id-card-login.vue
Normal file
372
pages/login/id-card-login.vue
Normal file
@@ -0,0 +1,372 @@
|
||||
<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'
|
||||
})
|
||||
|
||||
// 跳转到首页
|
||||
uni.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
} 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.idCardBase64) {
|
||||
// 直接通过参数传递
|
||||
processIdCardLogin(options.idCardBase64)
|
||||
} else {
|
||||
// 从当前URL中获取参数
|
||||
const currentPages = getCurrentPages()
|
||||
const currentPage = currentPages[currentPages.length - 1]
|
||||
const url = currentPage.$page.fullPath
|
||||
const params = getUrlParams(url)
|
||||
|
||||
if (params.idCardBase64) {
|
||||
processIdCardLogin(params.idCardBase64)
|
||||
} else {
|
||||
uni.showToast({
|
||||
title: '缺少身份证号码参数',
|
||||
icon: 'none'
|
||||
})
|
||||
setTimeout(() => {
|
||||
uni.navigateBack()
|
||||
}, 1500)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// 处理身份证登录流程
|
||||
const processIdCardLogin = async (idCardBase64) => {
|
||||
try {
|
||||
// 解码Base64身份证号码
|
||||
const idCard = decodeBase64(idCardBase64)
|
||||
|
||||
// 验证身份证号码格式(简单验证)
|
||||
if (!idCard || idCard.length < 15) {
|
||||
throw new Error('身份证号码格式不正确')
|
||||
}
|
||||
|
||||
// 调用登录接口
|
||||
await handleIdCardLogin(idCard)
|
||||
|
||||
} 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>
|
||||
Reference in New Issue
Block a user