Files
Driver-program/src/pages/login/index.vue
2026-02-07 16:11:40 +08:00

500 lines
15 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="login-page">
<!-- 头部区域 -->
<view class="header">
<view class="logo">
<text class="logo-text">华锐绿能燃料调度</text>
</view>
<text class="welcome-text">欢迎登录</text>
</view>
<!-- 登录方式切换 -->
<!-- <view class="login-mode-switch">
<view class="switch-tabs">
<view class="tab-item" :class="{ active: loginMode === 'password' }"
@click="switchLoginMode('password')">
<text class="tab-text">账号密码登录</text>
</view>
<view class="tab-item" :class="{ active: loginMode === 'phone' }" @click="switchLoginMode('phone')">
<text class="tab-text">手机号登录</text>
</view>
</view>
</view> -->
<!-- 登录表单 -->
<view class="login-form">
<!-- 账号密码登录 -->
<view class="password-login">
<view class="form-item">
<view class="input-label">
<My size="32" color="#999" />
<text class="label-text">手机号</text>
</view>
<nut-input v-model="loginForm.username" placeholder="请输入手机号" type="text" class="form-input" />
</view>
<view class="form-item">
<view class="input-label">
<Setting size="32" color="#999" />
<text class="label-text">密码</text>
</view>
<nut-input v-model="loginForm.password" placeholder="请输入密码" type="password" class="form-input" />
</view>
</view>
<!-- 忘记密码和手机验证码登录 -->
<view class="form-options">
<!-- <text class="forgot-password" @click="forgotPassword">忘记密码</text> -->
<!-- <text class="phone-login-link" @click="switchToPhoneLogin">手机验证码登录</text> -->
</view>
<!-- 登录按钮 -->
<button class="login-btn" @click="handleLogin" :disabled="isLoading">
{{ isLoading ? '登录中...' : '登录' }}
</button>
<!-- 注册链接 - 已关闭注册入口 -->
<!-- <view class="register-link" @click="goToRegister">
<text class="register-text">还没有账号</text>
<text class="register-btn">立即注册</text>
</view> -->
</view>
<!-- Toast 提示 -->
<nut-toast v-model:visible="showToast" :msg="toastMsg" />
</view>
</template>
<script setup>
import { ref, reactive } from 'vue'
import { Toast } from '@nutui/nutui-taro'
import { My, Setting } from '@nutui/icons-vue'
import Taro from '@tarojs/taro'
import { aesEncrypt } from '../../utils/crypto.js'
import { saveUserInfo } from '../../utils/auth.js'
import { authAPI, driverAPI } from '../../api/index.js'
// 账号密码登录表单数据
const loginForm = reactive({
username: '',
password: ''
})
// 状态管理
const isLoading = ref(false)
const showToast = ref(false)
const toastMsg = ref('')
// 显示提示信息
const showMessage = (msg) => {
toastMsg.value = msg
showToast.value = true
}
// 忘记密码
const forgotPassword = () => {
showMessage('忘记密码功能开发中...')
}
// 处理登录
const handleLogin = async () => {
// 账号密码登录验证
if (!loginForm.username.trim()) {
showMessage('请输入用户名')
return
}
if (!loginForm.password.trim()) {
showMessage('请输入密码')
return
}
if (loginForm.password.length < 6) {
showMessage('密码长度不能少于6位')
return
}
isLoading.value = true
try {
// 调用登录接口
// 对密码进行加密
const encryptedPassword = aesEncrypt(loginForm.password);
const loginData = {
username: loginForm.username,
password: encryptedPassword
}
const response = await authAPI.login(loginData)
if (response.statusCode === 200 && response.data) {
// 构建用户信息
const userInfo = {
isLogin: true,
token: response.data.access_token || response.data.token,
refreshToken: response.data.refresh_token,
expiresIn: response.data.expires_in,
tokenType: response.data.token_type || 'Bearer',
userId: response.data.userId || response.data.user_id,
username: loginForm.username,
avatar: response.data.avatar || '',
loginTime: new Date().getTime()
}
// 先保存token到本地存储供后续API调用使用
saveUserInfo(userInfo)
// 等待更长时间确保token完全生效
await new Promise(resolve => setTimeout(resolve, 1000))
// 检查用户是否为司机
try {
// 添加重试机制避免token未生效的问题
let driverResponse = null
let retryCount = 0
const maxRetries = 3
while (retryCount < maxRetries) {
try {
driverResponse = await driverAPI.getDriverInfo(userInfo.userId)
break // 成功获取,跳出循环
} catch (error) {
retryCount++
console.warn(`获取司机信息失败,重试第${retryCount}次:`, error)
if (retryCount < maxRetries) {
// 等待一段时间后重试
await new Promise(resolve => setTimeout(resolve, 500))
} else {
throw error // 重试次数用完,抛出错误
}
}
}
if (driverResponse.statusCode === 200 && driverResponse.data) {
// 检查是否包含司机ID
const hasDriverId = driverResponse.data.id || driverResponse.data.driverId ||
(driverResponse.data.data && (driverResponse.data.data.id || driverResponse.data.data.driverId))
if (hasDriverId) {
// 用户是司机且有司机ID登录成功
const updatedUserInfo = {
...userInfo,
isDriver: true,
driverInfo: driverResponse.data,
driverId: driverResponse.data.id || driverResponse.data.driverId ||
(driverResponse.data.data && (driverResponse.data.data.id || driverResponse.data.data.driverId))
}
saveUserInfo(updatedUserInfo)
showMessage('登录成功')
// 检查用户是否已完成实名认证
const driverStatus = driverResponse.data?.driverStatus ||
driverResponse.data?.data?.driverStatus
const isIdentityVerified = driverResponse.data?.identityVerified ||
driverResponse.data?.data?.identityVerified ||
updatedUserInfo.identityVerified
// 如果司机状态为1正常或者已经完成实名认证则跳转到首页
if (driverStatus === '1' || isIdentityVerified) {
// 用户已完成实名认证,跳转到首页
setTimeout(() => {
Taro.switchTab({ url: '/pages/index/index' })
}, 1000)
} else {
// 用户未完成实名认证,跳转到实名认证页面
setTimeout(() => {
Taro.navigateTo({ url: '/pages/realname/index?from=login' })
}, 1000)
}
} else {
// 用户不是司机或没有司机ID登录失败
showMessage('登录失败:您不是司机用户')
}
} else {
// 获取司机信息失败,登录失败
showMessage('登录失败:无法获取司机信息')
}
} catch (error) {
console.error('获取司机信息失败:', error)
// 检查是否是token相关错误
if (error.message && error.message.includes('用户凭证已过期')) {
// 如果是token过期错误可能是token还未完全生效重试一次
console.log('检测到token过期错误尝试重新获取司机信息...')
try {
// 再次等待并重试
await new Promise(resolve => setTimeout(resolve, 1000))
const retryResponse = await driverAPI.getDriverInfo(userInfo.userId)
if (retryResponse.statusCode === 200 && retryResponse.data) {
// 处理重试成功的响应
const hasDriverId = retryResponse.data.id || retryResponse.data.driverId ||
(retryResponse.data.data && (retryResponse.data.data.id || retryResponse.data.data.driverId))
if (hasDriverId) {
const updatedUserInfo = {
...userInfo,
isDriver: true,
driverInfo: retryResponse.data,
driverId: retryResponse.data.id || retryResponse.data.driverId ||
(retryResponse.data.data && (retryResponse.data.data.id || retryResponse.data.data.driverId))
}
saveUserInfo(updatedUserInfo)
showMessage('登录成功')
// 检查认证状态并跳转
const driverStatus = retryResponse.data?.driverStatus ||
retryResponse.data?.data?.driverStatus
const isIdentityVerified = retryResponse.data?.identityVerified ||
retryResponse.data?.data?.identityVerified ||
updatedUserInfo.identityVerified
if (driverStatus === '1' || isIdentityVerified) {
setTimeout(() => {
Taro.switchTab({ url: '/pages/index/index' })
}, 1000)
} else {
setTimeout(() => {
Taro.navigateTo({ url: '/pages/realname/index?from=login' })
}, 1000)
}
return
}
}
} catch (retryError) {
console.error('重试获取司机信息仍然失败:', retryError)
}
}
showMessage('登录失败:无法验证司机身份')
}
} else {
// 登录失败
const errorMsg = response.data?.msg || response.data?.message || '登录失败'
showMessage(errorMsg)
}
} catch (error) {
console.error('登录失败:', error)
showMessage('登录失败,请重试')
} finally {
isLoading.value = false
}
}
// 跳转到注册页面 - 已关闭注册入口
// const goToRegister = () => {
// Taro.navigateTo({ url: '/pages/register/index' })
// }
// 页面初始化完成,不再设置默认账号密码
</script>
<style>
.login-page {
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 0 40rpx;
}
/* 头部区域 */
.header {
text-align: center;
padding: 120rpx 0 60rpx;
}
.logo {
margin-bottom: 40rpx;
}
.logo-text {
font-size: 48rpx;
font-weight: bold;
color: white;
}
.welcome-text {
font-size: 32rpx;
color: rgba(255, 255, 255, 0.8);
}
/* 登录方式切换 */
.login-mode-switch {
margin-bottom: 40rpx;
}
.switch-tabs {
display: flex;
background: rgba(255, 255, 255, 0.2);
border-radius: 16rpx;
padding: 8rpx;
}
.tab-item {
flex: 1;
text-align: center;
padding: 20rpx;
border-radius: 12rpx;
transition: all 0.3s;
}
.tab-item.active {
background: white;
}
.tab-text {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.8);
font-weight: 500;
}
.tab-item.active .tab-text {
color: #667eea;
font-weight: bold;
}
/* 登录表单 */
.login-form {
background: white;
border-radius: 24rpx;
padding: 60rpx 40rpx;
box-shadow: 0 8rpx 32rpx rgba(0, 0, 0, 0.1);
}
.form-item {
margin-bottom: 40rpx;
}
.input-label {
display: flex;
align-items: center;
margin-bottom: 20rpx;
}
.label-text {
margin-left: 16rpx;
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.form-input {
width: 100%;
height: 80rpx;
border: 2rpx solid #f0f0f0;
border-radius: 16rpx;
padding: 20rpx 24rpx;
font-size: 28rpx;
line-height: 1.4;
background: #fff;
box-sizing: border-box;
/* 修复真机显示问题 */
-webkit-appearance: none;
appearance: none;
outline: none;
/* 修复字体渲染 */
font-family: inherit;
color: #333;
}
.form-input::placeholder {
color: #999;
font-size: 28rpx;
line-height: 1.4;
}
.form-input:focus {
border-color: #667eea;
outline: none;
}
/* 验证码输入 */
.verification-input {
display: flex;
gap: 20rpx;
align-items: center;
}
.code-input {
flex: 1;
}
.send-code-btn {
padding: 24rpx 32rpx;
background: #667eea;
color: white;
border: none;
border-radius: 16rpx;
font-size: 26rpx;
white-space: nowrap;
}
.send-code-btn:disabled {
background: #ccc;
color: #999;
}
/* 表单选项 */
.form-options {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 60rpx;
}
.forgot-password {
font-size: 28rpx;
color: #667eea;
}
.phone-login-link {
font-size: 28rpx;
color: #667eea;
}
/* 登录按钮 */
.login-btn {
width: 100%;
height: 88rpx;
background: #667eea;
color: white;
border: none;
border-radius: 16rpx;
font-size: 32rpx;
font-weight: bold;
margin-bottom: 40rpx;
}
.login-btn:disabled {
background: #ccc;
color: #999;
}
/* 注册链接 */
.register-link {
text-align: center;
}
.register-text {
font-size: 28rpx;
color: #666;
}
.register-btn {
font-size: 28rpx;
color: #667eea;
font-weight: bold;
margin-left: 8rpx;
}
</style>