|
|
@@ -236,6 +236,15 @@
|
|
|
<span>{{ $t('auth.telegramLogin') || 'Telegram 登录' }}</span>
|
|
|
</div>
|
|
|
|
|
|
+ <!-- Facebook 登录按钮 -->
|
|
|
+ <div class="oauth-btn facebook-btn" :class="{ loading: facebookLoading }" @click="handleFacebookLogin" v-if="facebookAppId">
|
|
|
+ <svg class="facebook-icon" viewBox="0 0 24 24" width="20" height="20">
|
|
|
+ <path fill="#fff" d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
|
|
|
+ </svg>
|
|
|
+ <span>{{ $t('auth.facebookLogin') || 'Facebook 登录' }}</span>
|
|
|
+ <van-loading v-if="facebookLoading" size="16px" color="#fff" />
|
|
|
+ </div>
|
|
|
+
|
|
|
<!-- TikTok 登录按钮 -->
|
|
|
<div class="oauth-btn tiktok-btn" :class="{ loading: tiktokLoading }" @click="handleTiktokLogin" v-if="tiktokClientKey">
|
|
|
<svg class="tiktok-icon" viewBox="0 0 24 24" width="20" height="20">
|
|
|
@@ -292,6 +301,8 @@ const telegramBotName = ref('');
|
|
|
const telegramBotId = ref('');
|
|
|
const tiktokLoading = ref(false);
|
|
|
const tiktokClientKey = ref('');
|
|
|
+const facebookLoading = ref(false);
|
|
|
+const facebookAppId = ref('');
|
|
|
|
|
|
const registerType = ref<'phone' | 'email'>('phone');
|
|
|
const showPassword = ref(false);
|
|
|
@@ -486,6 +497,12 @@ const initGoogleSignIn = async () => {
|
|
|
if (configRes.data.tiktokClientKey) {
|
|
|
tiktokClientKey.value = configRes.data.tiktokClientKey;
|
|
|
}
|
|
|
+
|
|
|
+ // 初始化 Facebook Login
|
|
|
+ if (configRes.data.facebookAppId) {
|
|
|
+ facebookAppId.value = configRes.data.facebookAppId;
|
|
|
+ initFacebookSDK(configRes.data.facebookAppId);
|
|
|
+ }
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.warn('Failed to load OAuth config:', error);
|
|
|
@@ -620,6 +637,82 @@ const handleTelegramCallback = async (user: any) => {
|
|
|
};
|
|
|
|
|
|
|
|
|
+// 初始化 Facebook SDK
|
|
|
+const initFacebookSDK = (appId: string) => {
|
|
|
+ if (document.getElementById('facebook-jssdk')) return;
|
|
|
+
|
|
|
+ window.fbAsyncInit = function() {
|
|
|
+ window.FB.init({
|
|
|
+ appId: appId,
|
|
|
+ cookie: true,
|
|
|
+ xfbml: false,
|
|
|
+ version: 'v19.0'
|
|
|
+ });
|
|
|
+ };
|
|
|
+
|
|
|
+ const script = document.createElement('script');
|
|
|
+ script.id = 'facebook-jssdk';
|
|
|
+ script.src = 'https://connect.facebook.net/en_US/sdk.js';
|
|
|
+ script.async = true;
|
|
|
+ script.defer = true;
|
|
|
+ document.head.appendChild(script);
|
|
|
+};
|
|
|
+
|
|
|
+// 触发 Facebook 登录
|
|
|
+const handleFacebookLogin = () => {
|
|
|
+ if (!facebookAppId.value) {
|
|
|
+ toast.error(t('auth.facebookNotConfigured') || 'Facebook 登录未配置');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!window.FB) {
|
|
|
+ toast.error('Facebook SDK 加载中,请稍后再试');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ facebookLoading.value = true;
|
|
|
+ window.FB.login((response: any) => {
|
|
|
+ if (response.authResponse) {
|
|
|
+ const accessToken = response.authResponse.accessToken;
|
|
|
+ window.FB.api('/me', { fields: 'id,name,email,picture.width(200)' }, (userInfo: any) => {
|
|
|
+ handleFacebookCallback(userInfo, accessToken);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ facebookLoading.value = false;
|
|
|
+ }
|
|
|
+ }, { scope: 'public_profile,email' });
|
|
|
+};
|
|
|
+
|
|
|
+// Facebook 登录回调
|
|
|
+const handleFacebookCallback = async (userInfo: any, accessToken: string) => {
|
|
|
+ try {
|
|
|
+ const inviteCode = phoneForm.inviteCode || emailForm.inviteCode || (route.query.smid as string) || '';
|
|
|
+ const res = await requestOAuthLogin({
|
|
|
+ provider: 'facebook',
|
|
|
+ openId: userInfo.id,
|
|
|
+ nickname: userInfo.name || '',
|
|
|
+ avatar: userInfo.picture?.data?.url || '',
|
|
|
+ email: userInfo.email || '',
|
|
|
+ extra: accessToken,
|
|
|
+ inviteCode
|
|
|
+ });
|
|
|
+
|
|
|
+ if (res.code === 200) {
|
|
|
+ localStorage.setItem('token', res.data.token);
|
|
|
+ userStore.setUserInfo(res.data.user);
|
|
|
+ toast.success(t('auth.loginSuccess'));
|
|
|
+ router.replace('/home');
|
|
|
+ } else {
|
|
|
+ toast.error(res.msg || t('auth.facebookLoginFailed') || 'Facebook 登录失败');
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('Facebook login error:', error);
|
|
|
+ toast.error(t('auth.facebookLoginFailed') || 'Facebook 登录失败');
|
|
|
+ } finally {
|
|
|
+ facebookLoading.value = false;
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
// 生成随机字符串
|
|
|
const generateRandomString = (length: number): string => {
|
|
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
|
@@ -873,10 +966,19 @@ onMounted(() => {
|
|
|
opacity: 0.7;
|
|
|
}
|
|
|
|
|
|
- .google-icon, .zalo-icon, .telegram-icon, .tiktok-icon {
|
|
|
+ .google-icon, .zalo-icon, .telegram-icon, .tiktok-icon, .facebook-icon {
|
|
|
flex-shrink: 0;
|
|
|
}
|
|
|
|
|
|
+ &.facebook-btn {
|
|
|
+ background: #1877F2;
|
|
|
+ color: #fff;
|
|
|
+
|
|
|
+ &:active {
|
|
|
+ background: #1565C0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
&.google-btn {
|
|
|
background: #fff;
|
|
|
color: #333;
|