bugfix: 谷歌登录

This commit is contained in:
zhangyahui
2025-11-05 10:39:35 +08:00
parent 7d44524046
commit 58d5873c6b

View File

@@ -1,5 +1,5 @@
<template>
<div class="Container" @click="handleContainerClick">
<div class="Container">
<div class="g_id_signin" id="g_id_signin"></div>
<div class="icon">
<img :src="google" class="google-icon" />
@@ -9,7 +9,6 @@
</template>
<script setup lang="ts">
import { reactive, onMounted, onBeforeUnmount } from 'vue'
import { showToast } from 'vant'
import { google } from '@/assets/base64'
// 定义 props
@@ -25,40 +24,11 @@ const emit = defineEmits<{
(e: 'googelLogin', code: string): void
}>()
// JWT 解码函数
function decodeJWT(token: string) {
const base64Url = token.split('.')[1]
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
// 使用类型断言来避免 deprecated 警告atob 在浏览器环境中仍然是最佳实践
const decoded = (atob as (data: string) => string)(base64)
const jsonPayload = decodeURIComponent(
decoded
.split('')
.map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
})
.join('')
)
return JSON.parse(jsonPayload)
}
// 处理 Google 登录回调
const handleCredentialResponse = async (response: { credential: string }) => {
// 获取回调响应的凭证数据 然后拿这个凭证给后台后台jwt进行解析获取登录信息
console.log('Encoded JWT ID token: ' + response.credential)
const responsePayload = decodeJWT(response.credential)
console.log('Decoded JWT ID token fields:')
console.log(' Full Name: ' + responsePayload.name)
console.log(' Given Name: ' + responsePayload.given_name)
console.log(' Family Name: ' + responsePayload.family_name)
console.log(' Unique ID: ' + responsePayload.sub)
console.log(' Profile image URL: ' + responsePayload.picture)
console.log(' Email: ' + responsePayload.email)
const code = response.credential
emit('googelLogin', code)
// 移除这行,保持按钮可以重复使用
// window.isAddGmail = false
window.isAddGmail = false
}
// 配置数据
@@ -68,168 +38,44 @@ const data = reactive({
script: null
})
console.log(import.meta.env.VITE_USER_NODE_ENV)
// 根据环境设置 Google Client ID
const GOOGLE_CLIENT_ID = '216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com'
// 等待 Google API 可用
const waitForGoogle = (): Promise<void> => {
return new Promise((resolve) => {
const google = window.google as any
if (google?.accounts?.id) {
resolve()
return
}
const checkInterval = setInterval(() => {
if (google?.accounts?.id) {
clearInterval(checkInterval)
resolve()
}
}, 50)
// 10秒超时
setTimeout(() => {
clearInterval(checkInterval)
resolve()
}, 10000)
})
}
// 初始化 Google API确保脚本加载和 API 可用)
const initializeGoogleAPI = async () => {
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
if (!existingScript) {
window.isAddGmail = true
await new Promise<void>((resolve) => {
const script = document.createElement('script')
script.onload = () => {
resolve()
}
script.onerror = () => {
console.error('Failed to load Google script')
resolve() // 仍然 resolve让后续代码处理
}
document.body.appendChild(script)
script.src = data.scriptSrc
})
}
// 等待 Google API 完全加载
await waitForGoogle()
const google = window.google as any
if (!google?.accounts?.id) {
console.error('Google API not available')
return false
}
return true
}
// 重新初始化 Google Sign-In每次调用时都重新初始化确保状态正确
const reinitializeGoogleSignIn = () => {
const google = window.google as any
if (!google?.accounts?.id) {
return false
}
// 每次重新初始化,确保状态正确
google.accounts.id.initialize({
client_id: GOOGLE_CLIENT_ID,
auto_select: false,
callback: handleCredentialResponse,
ux_mode: 'popup',
itp_support: true
})
return true
}
// 创建 Gmail 登录按钮
// 创建 Gmail 登录
const createGmailLogin = async () => {
const isReady = await initializeGoogleAPI()
if (!isReady) {
return
}
// 重新初始化确保状态正确
reinitializeGoogleSignIn()
// 等待一小段时间确保初始化完成
await new Promise(resolve => setTimeout(resolve, 100))
const google = window.google as any
// 然后渲染按钮
const buttonElement = document.querySelector('.Container #g_id_signin')
if (buttonElement) {
// 清除之前的内容,重新渲染
buttonElement.innerHTML = ''
google.accounts.id.renderButton(buttonElement, {
type: 'standard',
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
if (!window.isAddGmail) {
if (!existingScript) {
window.isAddGmail = true
await new Promise<void>((resolve) => {
const script = document.createElement('script')
script.onload = () => {
resolve()
}
document.body.appendChild(script)
script.src = data.scriptSrc
})
}
window.google.accounts.id.initialize({
// 主要就是填写client_id
client_id: GOOGLE_CLIENT_ID,
auto_select: false,
callback: handleCredentialResponse,
// context:"signin",
ux_mode: 'popup',
itp_support: true
})
console.log('创建谷歌登录按钮:', document.querySelector('.Container #g_id_signin'))
window.google.accounts.id.renderButton(document.querySelector('.Container #g_id_signin'), {
type: 'standard', //icon为只有一个icon
shape: 'circle',
theme: 'outline',
size: 'large',
logo_alignment: 'center'
})
} else {
console.error('Button element not found')
}
}
// 手动触发 Google 登录(用于处理弹窗关闭后无法再次触发的问题)
const triggerGoogleLogin = async () => {
const isReady = await initializeGoogleAPI()
if (!isReady) {
return
}
// 重新初始化确保状态正确
reinitializeGoogleSignIn()
const google = window.google as any
// 使用 prompt() 方法手动触发登录
try {
google.accounts.id.prompt((notification: any) => {
// 处理通知(例如用户关闭了弹窗)
if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
// 如果提示没有显示或被跳过,可以尝试使用按钮
console.log('Prompt not displayed, trying button click')
}
})
} catch (error) {
console.error('Error triggering Google login:', error)
// 如果 prompt() 失败,尝试重新渲染按钮
await createGmailLogin()
}
}
const toGmailLogin = () => {
showToast('Google login is not available yet')
}
// 处理容器点击事件(确保每次点击都能触发登录)
let isProcessingClick = false
const handleContainerClick = async () => {
// 防止重复点击
if (isProcessingClick) {
return
}
isProcessingClick = true
// 确保 API 已加载
const isReady = await initializeGoogleAPI()
if (isReady) {
// 重新初始化 API确保状态正确不重新渲染按钮
reinitializeGoogleSignIn()
}
// 短暂延迟后重置标志,允许下次点击
setTimeout(() => {
isProcessingClick = false
}, 200)
}
onBeforeUnmount(() => {
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
if (existingScript) {