bugfix: 谷歌登录
This commit is contained in:
27
env.d.ts
vendored
27
env.d.ts
vendored
@@ -1 +1,28 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
|
|
||||||
|
// Google Identity Services 类型声明
|
||||||
|
interface GoogleAccounts {
|
||||||
|
accounts: {
|
||||||
|
id: {
|
||||||
|
initialize: (config: {
|
||||||
|
client_id: string
|
||||||
|
auto_select?: boolean
|
||||||
|
callback: (response: { credential: string }) => void
|
||||||
|
ux_mode?: 'popup' | 'redirect'
|
||||||
|
itp_support?: boolean
|
||||||
|
}) => void
|
||||||
|
renderButton: (element: Element | null, config: {
|
||||||
|
type?: 'standard' | 'icon'
|
||||||
|
shape?: 'rectangular' | 'pill' | 'circle' | 'square'
|
||||||
|
theme?: 'outline' | 'filled_blue' | 'filled_black'
|
||||||
|
size?: 'large' | 'medium' | 'small'
|
||||||
|
logo_alignment?: 'left' | 'center'
|
||||||
|
}) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Window {
|
||||||
|
google?: GoogleAccounts
|
||||||
|
isAddGmail?: boolean
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="Container">
|
<div class="Container" @click="handleContainerClick">
|
||||||
<div class="g_id_signin" id="g_id_signin"></div>
|
<div class="g_id_signin" id="g_id_signin"></div>
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
<img :src="google" class="google-icon" />
|
<img :src="google" class="google-icon" />
|
||||||
@@ -29,8 +29,10 @@ const emit = defineEmits<{
|
|||||||
function decodeJWT(token: string) {
|
function decodeJWT(token: string) {
|
||||||
const base64Url = token.split('.')[1]
|
const base64Url = token.split('.')[1]
|
||||||
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
|
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')
|
||||||
|
// 使用类型断言来避免 deprecated 警告,atob 在浏览器环境中仍然是最佳实践
|
||||||
|
const decoded = (atob as (data: string) => string)(base64)
|
||||||
const jsonPayload = decodeURIComponent(
|
const jsonPayload = decodeURIComponent(
|
||||||
atob(base64)
|
decoded
|
||||||
.split('')
|
.split('')
|
||||||
.map(function (c) {
|
.map(function (c) {
|
||||||
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
|
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)
|
||||||
@@ -55,7 +57,8 @@ const handleCredentialResponse = async (response: { credential: string }) => {
|
|||||||
|
|
||||||
const code = response.credential
|
const code = response.credential
|
||||||
emit('googelLogin', code)
|
emit('googelLogin', code)
|
||||||
window.isAddGmail = false
|
// 移除这行,保持按钮可以重复使用
|
||||||
|
// window.isAddGmail = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 配置数据
|
// 配置数据
|
||||||
@@ -70,10 +73,31 @@ console.log(import.meta.env.VITE_USER_NODE_ENV)
|
|||||||
// 根据环境设置 Google Client ID
|
// 根据环境设置 Google Client ID
|
||||||
const GOOGLE_CLIENT_ID = '216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com'
|
const GOOGLE_CLIENT_ID = '216037134725-7q8vqp0ohtmohlosltkfg7bd2v29rm5a.apps.googleusercontent.com'
|
||||||
|
|
||||||
// 创建 Gmail 登录
|
// 等待 Google API 可用
|
||||||
const createGmailLogin = async () => {
|
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}"]`)
|
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
|
||||||
if (!window.isAddGmail) {
|
|
||||||
if (!existingScript) {
|
if (!existingScript) {
|
||||||
window.isAddGmail = true
|
window.isAddGmail = true
|
||||||
await new Promise<void>((resolve) => {
|
await new Promise<void>((resolve) => {
|
||||||
@@ -81,27 +105,101 @@ const createGmailLogin = async () => {
|
|||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
script.onerror = () => {
|
||||||
|
console.error('Failed to load Google script')
|
||||||
|
resolve() // 仍然 resolve,让后续代码处理
|
||||||
|
}
|
||||||
document.body.appendChild(script)
|
document.body.appendChild(script)
|
||||||
script.src = data.scriptSrc
|
script.src = data.scriptSrc
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
window.google.accounts.id.initialize({
|
|
||||||
// 主要就是填写client_id
|
// 等待 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,
|
client_id: GOOGLE_CLIENT_ID,
|
||||||
auto_select: false,
|
auto_select: false,
|
||||||
callback: handleCredentialResponse,
|
callback: handleCredentialResponse,
|
||||||
// context:"signin",
|
|
||||||
ux_mode: 'popup',
|
ux_mode: 'popup',
|
||||||
itp_support: true
|
itp_support: true
|
||||||
})
|
})
|
||||||
console.log(document.querySelector('.Container #g_id_signin'))
|
|
||||||
window.google.accounts.id.renderButton(document.querySelector('.Container #g_id_signin'), {
|
return true
|
||||||
type: 'standard', //icon为只有一个icon
|
}
|
||||||
|
|
||||||
|
// 创建 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',
|
||||||
shape: 'circle',
|
shape: 'circle',
|
||||||
theme: 'outline',
|
theme: 'outline',
|
||||||
size: 'large',
|
size: 'large',
|
||||||
logo_alignment: 'center'
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +207,29 @@ const toGmailLogin = () => {
|
|||||||
showToast('Google login is not available yet')
|
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(() => {
|
onBeforeUnmount(() => {
|
||||||
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
|
const existingScript = document.querySelector(`script[src="${data.scriptSrc}"]`)
|
||||||
if (existingScript) {
|
if (existingScript) {
|
||||||
|
|||||||
Reference in New Issue
Block a user