This commit is contained in:
2026-07-20 11:56:02 +08:00
commit 2dcae4165b
176 changed files with 34633 additions and 0 deletions

298
pages/login/index.vue Normal file
View File

@@ -0,0 +1,298 @@
<template>
<view class="page">
<view class="hero-card">
<view class="hero-title">进入智慧团委小程序</view>
<view class="hero-desc">支持手机号密码登录也支持微信手机号授权登录</view>
</view>
<view class="login-card">
<view class="tab-row">
<view
class="tab-item"
:class="{ 'tab-item--active': loginMode === 'password' }"
@tap="loginMode = 'password'"
>
手机号密码登录
</view>
<view
class="tab-item"
:class="{ 'tab-item--active': loginMode === 'wechat' }"
@tap="loginMode = 'wechat'"
>
微信授权登录
</view>
</view>
<view v-if="loginMode === 'password'" class="form-section">
<uv-input
v-model.trim="form.username"
class="field-input"
type="text"
placeholder="请输入手机号或账号"
:maxlength="-1"
border="none"
/>
<uv-input
v-model="form.password"
class="field-input"
type="password"
placeholder="请输入密码"
:maxlength="-1"
border="none"
password
/>
<view class="submit-btn" :class="{ 'submit-btn--loading': loading }" @tap="submitPasswordLogin">
{{ loading ? '登录中...' : '立即登录' }}
</view>
</view>
<view v-else class="form-section">
<view class="wechat-intro">授权后将使用微信手机号完成登录</view>
<button
class="submit-btn submit-btn--wechat"
:disabled="loading"
open-type="getPhoneNumber"
@getphonenumber="handleWxPhoneLogin"
>
{{ loading ? '登录中...' : '微信授权登录' }}
</button>
</view>
</view>
</view>
</template>
<script>
import { loginByMpWxPhone, loginByPassword } from './service'
import { hasToken, setAuthInfo } from '../../utils/request'
export default {
data() {
return {
loginMode: 'password',
loading: false,
redirect: '',
wxCode: '',
form: {
username: '',
password: ''
}
}
},
onLoad(options) {
this.redirect = decodeURIComponent((options && options.redirect) || '')
},
onShow() {
if (hasToken()) {
this.navigateAfterLogin()
return
}
this.refreshWxCode()
},
methods: {
showToast(title) {
uni.showToast({
title,
icon: 'none'
})
},
refreshWxCode() {
uni.login({
success: (res) => {
this.wxCode = (res && res.code) || ''
}
})
},
navigateAfterLogin() {
const url = this.redirect || '/pages/index/index'
uni.reLaunch({
url
})
},
async submitPasswordLogin() {
if (this.loading) {
return
}
if (!this.form.username) {
this.showToast('请输入手机号或账号')
return
}
if (!this.form.password) {
this.showToast('请输入密码')
return
}
this.loading = true
try {
const result = await loginByPassword({
username: this.form.username,
password: this.form.password
})
setAuthInfo(result)
this.showToast('登录成功')
setTimeout(() => {
this.navigateAfterLogin()
}, 300)
} catch (error) {
this.showToast((error && error.message) || '登录失败')
} finally {
this.loading = false
}
},
async handleWxPhoneLogin(event) {
if (this.loading) {
return
}
const detail = (event && event.detail) || {}
if (!detail.code) {
this.showToast(detail.errMsg || '未获取到微信手机号凭证')
return
}
this.loading = true
try {
if (!this.wxCode) {
await new Promise((resolve) => {
uni.login({
success: (res) => {
this.wxCode = (res && res.code) || ''
resolve()
},
fail: () => resolve()
})
})
}
const result = await loginByMpWxPhone({
phoneCode: detail.code,
code: this.wxCode || undefined
})
setAuthInfo(result)
this.showToast('登录成功')
setTimeout(() => {
this.navigateAfterLogin()
}, 300)
} catch (error) {
this.showToast((error && error.message) || '微信登录失败')
this.refreshWxCode()
} finally {
this.loading = false
}
}
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
padding: 28rpx 24rpx 40rpx;
background:
radial-gradient(circle at top left, rgba(20, 150, 242, 0.14), transparent 30%),
linear-gradient(180deg, #f5fbff 0%, #eef7ff 100%);
}
.hero-card,
.login-card {
border-radius: 32rpx;
box-shadow: 0 18rpx 40rpx rgba(20, 118, 194, 0.12);
}
.hero-card {
padding: 34rpx 30rpx;
background: linear-gradient(145deg, #0d6fba 0%, #1496f2 58%, #5bc2ff 100%);
color: #fff;
}
.hero-badge {
display: inline-flex;
padding: 10rpx 18rpx;
border-radius: 999rpx;
background: rgba(255, 255, 255, 0.16);
font-size: 22rpx;
}
.hero-title {
margin-top: 22rpx;
font-size: 42rpx;
font-weight: 700;
}
.hero-desc {
margin-top: 14rpx;
font-size: 24rpx;
line-height: 1.7;
color: rgba(255, 255, 255, 0.86);
}
.login-card {
margin-top: 24rpx;
padding: 28rpx 24rpx;
background: rgba(255, 255, 255, 0.94);
}
.tab-row {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 14rpx;
}
.tab-item {
height: 82rpx;
border-radius: 22rpx;
background: #edf5ff;
color: #1496f2;
font-size: 24rpx;
font-weight: 600;
line-height: 82rpx;
text-align: center;
}
.tab-item--active {
background: linear-gradient(135deg, #1496f2, #0d6fba);
color: #fff;
}
.form-section {
margin-top: 22rpx;
}
:deep(.field-input.uv-input) {
width: 100%;
height: 88rpx;
margin-top: 16rpx;
padding: 0 24rpx !important;
border-radius: 24rpx;
background: #f8fbff !important;
border: 1rpx solid rgba(20, 150, 242, 0.12) !important;
}
:deep(.field-input.uv-input .uv-input__content__field-wrapper__field) {
font-size: 24rpx;
color: #1f2329;
}
.wechat-intro {
font-size: 24rpx;
line-height: 1.7;
color: #667085;
}
.submit-btn {
width: 100%;
height: 88rpx;
margin-top: 22rpx;
border: none;
border-radius: 24rpx;
background: linear-gradient(135deg, #1496f2, #0d6fba);
color: #fff;
font-size: 26rpx;
font-weight: 700;
line-height: 88rpx;
text-align: center;
}
.submit-btn--wechat {
background: linear-gradient(135deg, #1dbf73, #12a150);
}
.submit-btn--loading {
opacity: 0.72;
}
</style>