<script setup lang="ts">
|
import { loginByWx } from '@/api/auth'
|
import { useMiniAuthStore } from '@/store/auth'
|
import { finishMiniLogin, getApiErrorCode, getWxLoginCode, MINI_PHONE_AUTH_REQUIRED } from '@/utils/mini-login'
|
import { normalizeProfileDisplayName } from '@/types/auth'
|
|
const emit = defineEmits<{
|
(e: 'login-success'): void
|
}>()
|
|
const authStore = useMiniAuthStore()
|
const router = useRouter()
|
const loginSubmitting = ref(false)
|
|
const visible = computed(() => authStore.loginPromptVisible)
|
const needPhoneAuthorize = computed(() => authStore.needPhoneAuthorize)
|
const message = computed(() => {
|
if (needPhoneAuthorize.value) {
|
return '首次登录需授权手机号完成身份识别'
|
}
|
return authStore.authPromptMessage || '您还未登录,请先登录'
|
})
|
|
function hideLoginPrompt() {
|
authStore.hideLoginPrompt()
|
}
|
|
function shouldForceEditProfile() {
|
return !normalizeProfileDisplayName(authStore.profile?.displayName)
|
}
|
|
function openProfileEditorIfNeeded() {
|
if (!shouldForceEditProfile()) {
|
return false
|
}
|
uni.showToast({
|
title: '请先完善个人资料',
|
icon: 'none',
|
})
|
router.push({ name: 'profile' })
|
return true
|
}
|
|
async function handleStartLogin() {
|
if (loginSubmitting.value) {
|
return
|
}
|
|
loginSubmitting.value = true
|
try {
|
const wxCode = await getWxLoginCode()
|
const loginData = await loginByWx({ wxCode })
|
await finishMiniLogin(loginData)
|
hideLoginPrompt()
|
uni.$emit('mini-login-success')
|
emit('login-success')
|
if (openProfileEditorIfNeeded()) {
|
return
|
}
|
uni.showToast({
|
title: '登录成功',
|
icon: 'success',
|
})
|
}
|
catch (error) {
|
if (getApiErrorCode(error) === MINI_PHONE_AUTH_REQUIRED) {
|
authStore.setNeedPhoneAuthorize(true)
|
return
|
}
|
uni.showToast({
|
title: error instanceof Error ? error.message : '登录失败',
|
icon: 'none',
|
})
|
}
|
finally {
|
loginSubmitting.value = false
|
}
|
}
|
|
async function handlePhoneAuthorize(event: any) {
|
if (loginSubmitting.value) {
|
return
|
}
|
const phoneCode = event?.detail?.code
|
if (!phoneCode) {
|
uni.showToast({
|
title: '未获取到手机号授权',
|
icon: 'none',
|
})
|
return
|
}
|
|
loginSubmitting.value = true
|
try {
|
const wxCode = await getWxLoginCode()
|
const loginData = await loginByWx({ wxCode, phoneCode })
|
await finishMiniLogin(loginData)
|
hideLoginPrompt()
|
uni.$emit('mini-login-success')
|
emit('login-success')
|
if (openProfileEditorIfNeeded()) {
|
return
|
}
|
uni.showToast({
|
title: '登录成功',
|
icon: 'success',
|
})
|
}
|
catch (error) {
|
uni.showToast({
|
title: error instanceof Error ? error.message : '登录失败',
|
icon: 'none',
|
})
|
}
|
finally {
|
loginSubmitting.value = false
|
}
|
}
|
</script>
|
|
<template>
|
<view v-if="visible" class="fixed inset-0 z-40 bg-[rgba(0,0,0,0.55)]" @click="!needPhoneAuthorize && hideLoginPrompt()" />
|
|
<view
|
v-if="visible"
|
class="fixed left-[50%] top-[50%] z-50 w-[520rpx] translate-x-[-50%] translate-y-[-50%] rounded-[28rpx] bg-white px-[40rpx] pb-[36rpx] pt-[28rpx]"
|
>
|
<view class="mb-[16rpx] text-center text-[34rpx] text-[#1A1A1A] font-medium">
|
提示
|
</view>
|
<view class="flex flex-col items-center">
|
<image src="/static/home/tips.png" class="mb-[24rpx] h-[144rpx] w-[144rpx]" mode="aspectFit" />
|
<text class="mb-[44rpx] text-[28rpx] text-[#4A4A4A]">
|
{{ message }}
|
</text>
|
</view>
|
<view class="flex items-center justify-between gap-[20rpx]">
|
<view
|
class="h-[80rpx] flex flex-1 items-center justify-center rounded-full bg-[#F2F2F2] text-[30rpx] text-[#666666]"
|
@click="hideLoginPrompt"
|
>
|
再想想
|
</view>
|
<button
|
v-if="needPhoneAuthorize"
|
class="m-0 h-[80rpx] flex flex-1 items-center justify-center rounded-full border-none bg-[#0C6FFF] p-0 text-[30rpx] text-white after:border-none"
|
:disabled="loginSubmitting"
|
open-type="getPhoneNumber"
|
@getphonenumber="handlePhoneAuthorize"
|
>
|
{{ loginSubmitting ? '授权中...' : '授权手机号' }}
|
</button>
|
<view
|
v-else
|
class="h-[80rpx] flex flex-1 items-center justify-center rounded-full bg-[#0C6FFF] text-[30rpx] text-white"
|
@click="handleStartLogin"
|
>
|
{{ loginSubmitting ? '登录中...' : '去登录' }}
|
</view>
|
</view>
|
</view>
|
</template>
|