All checks were successful
continuous-integration/drone/push Build is passing
240 lines
4.9 KiB
Vue
240 lines
4.9 KiB
Vue
<template>
|
||
<view class="login-page">
|
||
<!-- 自定义导航栏 -->
|
||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="navbar-content">
|
||
<view class="nav-back" @click="goBack">
|
||
<text class="back-arrow">‹</text>
|
||
</view>
|
||
<text class="navbar-title">登录</text>
|
||
<view class="nav-placeholder"></view>
|
||
</view>
|
||
</view>
|
||
<view :style="{ height: (statusBarHeight + 44) + 'px' }"></view>
|
||
<!-- Logo 和应用名称 -->
|
||
<view class="login-header">
|
||
<image class="login-logo" src="/static/logo.png" mode="aspectFit"></image>
|
||
<text class="login-title">校园跑腿</text>
|
||
<text class="login-subtitle">便捷校园生活,从这里开始</text>
|
||
</view>
|
||
|
||
<!-- 登录按钮区域 -->
|
||
<view class="login-actions">
|
||
<button
|
||
class="login-btn"
|
||
@click="onWxLogin"
|
||
:loading="loading"
|
||
:disabled="loading"
|
||
>
|
||
微信一键登录
|
||
</button>
|
||
<text class="login-tip">{{ tipText }}</text>
|
||
</view>
|
||
|
||
<!-- 底部协议 -->
|
||
<view class="login-footer">
|
||
<text class="footer-text">登录即表示同意</text>
|
||
<text class="footer-link" @click="goAgreement">《用户协议》</text>
|
||
<text class="footer-text">和</text>
|
||
<text class="footer-link" @click="goPrivacy">《隐私政策》</text>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref } from 'vue'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { wxLogin } from '@/utils/api'
|
||
|
||
const userStore = useUserStore()
|
||
const loading = ref(false)
|
||
const tipText = ref('使用微信账号快速登录')
|
||
const statusBarHeight = ref(0)
|
||
|
||
// 获取状态栏高度
|
||
const sysInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = sysInfo.statusBarHeight || 0
|
||
|
||
/** 返回上一页 */
|
||
function goBack() {
|
||
const pages = getCurrentPages()
|
||
if (pages.length > 1) {
|
||
uni.navigateBack()
|
||
} else {
|
||
uni.switchTab({ url: '/pages/index/index' })
|
||
}
|
||
}
|
||
|
||
/** 微信一键登录 */
|
||
async function onWxLogin() {
|
||
loading.value = true
|
||
tipText.value = '登录中...'
|
||
try {
|
||
// 调用 wx.login 获取 code
|
||
const loginRes = await new Promise((resolve, reject) => {
|
||
uni.login({
|
||
provider: 'weixin',
|
||
success: resolve,
|
||
fail: reject
|
||
})
|
||
})
|
||
if (!loginRes?.code) {
|
||
tipText.value = '获取微信授权失败,请重试'
|
||
return
|
||
}
|
||
// 发送 code 到后端换取 token
|
||
console.log('[登录] 获取到 code:', loginRes.code)
|
||
const res = await wxLogin({ code: loginRes.code })
|
||
if (res.token && res.userInfo) {
|
||
userStore.setLoginInfo(res.token, res.userInfo)
|
||
uni.showToast({ title: '登录成功', icon: 'success' })
|
||
// 检查是否有登录前的回跳页面
|
||
const redirect = uni.getStorageSync('loginRedirect')
|
||
if (redirect) {
|
||
uni.removeStorageSync('loginRedirect')
|
||
uni.redirectTo({ url: redirect })
|
||
} else {
|
||
uni.reLaunch({ url: '/pages/index/index' })
|
||
}
|
||
} else {
|
||
tipText.value = '登录失败,请重试'
|
||
}
|
||
} catch (e) {
|
||
console.error('登录失败:', e)
|
||
tipText.value = '登录失败,请重试'
|
||
} finally {
|
||
loading.value = false
|
||
}
|
||
}
|
||
|
||
/** 跳转用户协议 */
|
||
function goAgreement() {
|
||
uni.navigateTo({ url: '/pages/config/agreement' })
|
||
}
|
||
|
||
/** 跳转隐私政策 */
|
||
function goPrivacy() {
|
||
uni.navigateTo({ url: '/pages/config/privacy' })
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.login-page {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(180deg, #FFF8E1 0%, #FFFFFF 40%);
|
||
padding: 0 60rpx;
|
||
}
|
||
|
||
/* 自定义导航栏 */
|
||
.custom-navbar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
z-index: 999;
|
||
}
|
||
.navbar-content {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 20rpx;
|
||
}
|
||
.nav-back {
|
||
width: 60rpx;
|
||
height: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
.back-arrow {
|
||
font-size: 48rpx;
|
||
color: #333;
|
||
font-weight: bold;
|
||
}
|
||
.navbar-title {
|
||
font-size: 34rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
.nav-placeholder {
|
||
width: 60rpx;
|
||
}
|
||
|
||
.login-header {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
margin-bottom: 120rpx;
|
||
}
|
||
|
||
.login-logo {
|
||
width: 160rpx;
|
||
height: 160rpx;
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.login-title {
|
||
font-size: 44rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.login-subtitle {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
}
|
||
|
||
.login-actions {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.login-btn {
|
||
width: 100%;
|
||
height: 96rpx;
|
||
line-height: 96rpx;
|
||
background: linear-gradient(135deg, #FFB700, #FF9500);
|
||
color: #fff;
|
||
font-size: 34rpx;
|
||
font-weight: bold;
|
||
border-radius: 48rpx;
|
||
border: none;
|
||
letter-spacing: 4rpx;
|
||
}
|
||
|
||
.login-btn::after {
|
||
border: none;
|
||
}
|
||
|
||
.login-tip {
|
||
font-size: 24rpx;
|
||
color: #bbb;
|
||
margin-top: 24rpx;
|
||
}
|
||
|
||
.login-footer {
|
||
position: fixed;
|
||
bottom: 60rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.footer-text {
|
||
font-size: 22rpx;
|
||
color: #ccc;
|
||
}
|
||
|
||
.footer-link {
|
||
font-size: 22rpx;
|
||
color: #FFB700;
|
||
}
|
||
</style>
|