feat(miniprogram): add phone quick login button on login page.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuzilongandCursor committed 2026-09-18 11:15:47 +08:00
1 parent 6f39801c63
commit b5a58583bd
2 files changed
+142 -4

No files matched your search

+141 -1
View File
@@ -15,6 +15,7 @@ const isLoading = ref(false)
const agreeProtocol = ref(false)
const loginDisabled = computed(() => isLoading.value)
const protocolDialogVisible = ref(false)
const protocolDialogForWechat = ref(false)
let protocolDialogResolver = null
onShow(() => {
@@ -28,6 +29,7 @@ const loginPageStyle = computed(() => ({ '--theme-color': '#0a9f6d' }))
const handleSubmit = async () => {
if (!agreeProtocol.value) {
protocolDialogForWechat.value = false
const shouldContinue = await new Promise((resolve) => {
protocolDialogResolver = resolve
protocolDialogVisible.value = true
@@ -72,11 +74,61 @@ const toggleProtocolAgreement = () => {
const resolveProtocolDialog = (confirmed) => {
protocolDialogVisible.value = false
protocolDialogForWechat.value = false
if (protocolDialogResolver) {
protocolDialogResolver(confirmed)
protocolDialogResolver = null
}
}
const onWechatGate = () => {
if (isLoading.value) return
protocolDialogForWechat.value = true
protocolDialogVisible.value = true
}
const onAgreeGetPhoneNumber = (e) => {
agreeProtocol.value = true
protocolDialogVisible.value = false
protocolDialogForWechat.value = false
onGetPhoneNumber(e)
}
const onGetPhoneNumber = async (e) => {
if (isLoading.value) return
if (!agreeProtocol.value) {
onWechatGate()
return
}
const detail = (e && e.detail) || {}
const errMsg = detail.errMsg || ''
if (errMsg && errMsg.indexOf('ok') === -1) {
uni.showToast({ title: '需要授权手机号,或请使用账号密码登录', icon: 'none' })
return
}
const phoneCode = detail.code
if (!phoneCode) {
uni.showToast({ title: '需要授权手机号,或请使用账号密码登录', icon: 'none' })
return
}
isLoading.value = true
try {
const loginRes = await new Promise((resolve, reject) => {
uni.login({ provider: 'weixin', success: resolve, fail: reject })
})
const ok = await userStore.wechatLogin({
loginCode: loginRes.code,
phoneCode
})
if (ok) {
userStore.navigateToHome()
}
} catch (err) {
uni.showToast({ title: (err && err.message) || '登录失败', icon: 'none' })
} finally {
isLoading.value = false
}
}
</script>
<template>
@@ -144,6 +196,26 @@ const resolveProtocolDialog = (confirmed) => {
<text class="link" @tap="goPrivacyPolicy">《隐私政策》</text>
</view>
</view>
<view class="login-divider">或</view>
<button
v-if="agreeProtocol"
class="login-wechat"
:disabled="isLoading"
open-type="getPhoneNumber"
@getphonenumber="onGetPhoneNumber"
>
<text class="login-wechat__label">手机号快捷登录</text>
</button>
<view
v-else
class="login-wechat"
:class="{ 'is-disabled': isLoading }"
@tap="onWechatGate"
>
<text class="login-wechat__label">手机号快捷登录</text>
</view>
</view>
<view v-if="protocolDialogVisible" class="protocol-dialog-mask" @tap="resolveProtocolDialog(false)">
@@ -152,7 +224,21 @@ const resolveProtocolDialog = (confirmed) => {
<text class="protocol-dialog__desc">登录前请先同意《用户服务协议》和《隐私政策》</text>
<view class="protocol-dialog__actions">
<view class="protocol-dialog__btn protocol-dialog__btn--cancel" @tap="resolveProtocolDialog(false)">否</view>
<view class="protocol-dialog__btn protocol-dialog__btn--confirm" @tap="resolveProtocolDialog(true)">是,继续登录</view>
<button
v-if="protocolDialogForWechat"
class="protocol-dialog__btn protocol-dialog__btn--confirm"
open-type="getPhoneNumber"
@getphonenumber="onAgreeGetPhoneNumber"
>
同意并登录
</button>
<view
v-else
class="protocol-dialog__btn protocol-dialog__btn--confirm"
@tap="resolveProtocolDialog(true)"
>
是,继续登录
</view>
</view>
</view>
</view>
@@ -468,6 +554,60 @@ const resolveProtocolDialog = (confirmed) => {
.protocol-dialog__btn--confirm {
background: linear-gradient(135deg, var(--theme-color) 0%, #07c160 100%);
color: #fff;
border: none;
margin: 0;
padding: 0;
line-height: normal;
}
button.protocol-dialog__btn--confirm::after {
border: none;
}
.login-divider {
display: flex;
align-items: center;
gap: 24rpx;
margin: 44rpx 0 28rpx;
width: 100%;
font-size: 24rpx;
color: #94a3b8;
}
.login-divider::before,
.login-divider::after {
content: '';
flex: 1;
height: 1px;
background: #e2e8f0;
}
.login-wechat {
height: 88rpx;
border-radius: 24rpx;
border: 1px solid #e2e8f0;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
width: 100%;
margin: 0;
padding: 0;
line-height: normal;
box-sizing: border-box;
font-size: 28rpx;
font-weight: 500;
color: #1e293b;
}
button.login-wechat::after {
border: none;
}
.login-wechat__label {
font-size: 28rpx;
font-weight: 500;
color: #1e293b;
}
</style>
+1 -3
View File
@@ -130,8 +130,8 @@ export const useUserStore = defineStore('user', () => {
}
}
/** 手机号快捷登录;loading 由登录页控制,此处不改 isLoading */
async function wechatLogin(params) {
isLoading.value = true
try {
const res = await request({
url: AUTH_API.WECHAT_LOGIN,
@@ -156,8 +156,6 @@ export const useUserStore = defineStore('user', () => {
} catch (e) {
uni.showToast({ title: (e && e.message) || '登录失败', icon: 'none' })
return false
} finally {
isLoading.value = false
}
}