From c5b904e15943095051ebf2302c13ad5f3389a1c6 Mon Sep 17 00:00:00 2001 From: admin <1297598740@qq.com> Date: Thu, 29 Jan 2026 13:13:34 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8C=85=E6=8B=AC?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E3=80=81=E6=B3=A8=E5=86=8C=E3=80=81OAuth?= =?UTF-8?q?=E5=9B=9E=E8=B0=83=E5=92=8C=E7=9B=B8=E5=85=B3=E8=B7=AF=E7=94=B1?= =?UTF-8?q?=E5=8F=8A=E6=9C=8D=E5=8A=A1=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/GitHubCallback/index.ts | 1 - src/pages/Login/Login.css | 26 ++++++++++ src/pages/Login/Login.tsx | 9 ++++ .../OAuthCallback.css} | 4 +- .../OAuthCallback.tsx} | 33 +++++++++---- src/pages/OAuthCallback/index.ts | 1 + src/router/index.tsx | 8 +++- src/services/authService.ts | 47 +++++++++++++++++++ 8 files changed, 114 insertions(+), 15 deletions(-) delete mode 100644 src/pages/GitHubCallback/index.ts rename src/pages/{GitHubCallback/GitHubCallback.css => OAuthCallback/OAuthCallback.css} (93%) rename src/pages/{GitHubCallback/GitHubCallback.tsx => OAuthCallback/OAuthCallback.tsx} (63%) create mode 100644 src/pages/OAuthCallback/index.ts diff --git a/src/pages/GitHubCallback/index.ts b/src/pages/GitHubCallback/index.ts deleted file mode 100644 index 9606899..0000000 --- a/src/pages/GitHubCallback/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './GitHubCallback'; diff --git a/src/pages/Login/Login.css b/src/pages/Login/Login.css index 2ba06ad..9bc5c3d 100644 --- a/src/pages/Login/Login.css +++ b/src/pages/Login/Login.css @@ -415,6 +415,32 @@ transform: rotate(-8deg) scale(1.1); } + +/* Gitee Button */ +.login-button--gitee { + background: #ffffff; + color: #c71d23; + border: 1.5px solid #e5e7eb; + margin-top: 0.5rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04); +} + +.login-button--gitee:hover { + background: #fef2f2; + border-color: #fecaca; + color: #b91c1c; + transform: translateY(-2px); + box-shadow: 0 6px 16px rgba(199, 29, 35, 0.12); +} + +.login-button--gitee svg { + transition: transform 0.3s; +} + +.login-button--gitee:hover svg { + transform: scale(1.1); +} + /* ===================== DIVIDER ===================== */ .login-divider { display: flex; diff --git a/src/pages/Login/Login.tsx b/src/pages/Login/Login.tsx index 33bacb8..18c9c2e 100644 --- a/src/pages/Login/Login.tsx +++ b/src/pages/Login/Login.tsx @@ -176,6 +176,15 @@ export default function Login({ mode = 'login' }: LoginProps) { 使用 GitHub 登录 + + + + 使用 Gitee 登录 +
diff --git a/src/pages/GitHubCallback/GitHubCallback.css b/src/pages/OAuthCallback/OAuthCallback.css similarity index 93% rename from src/pages/GitHubCallback/GitHubCallback.css rename to src/pages/OAuthCallback/OAuthCallback.css index 8cb3874..c67a65f 100644 --- a/src/pages/GitHubCallback/GitHubCallback.css +++ b/src/pages/OAuthCallback/OAuthCallback.css @@ -1,4 +1,4 @@ -.github-callback-page { +.oauth-callback-page { min-height: 100vh; display: flex; align-items: center; @@ -7,7 +7,7 @@ padding: 1rem; } -.github-callback-container { +.oauth-callback-container { background: var(--card-bg); border-radius: 1rem; padding: 3rem 2rem; diff --git a/src/pages/GitHubCallback/GitHubCallback.tsx b/src/pages/OAuthCallback/OAuthCallback.tsx similarity index 63% rename from src/pages/GitHubCallback/GitHubCallback.tsx rename to src/pages/OAuthCallback/OAuthCallback.tsx index a3d3af4..8b0eb8d 100644 --- a/src/pages/GitHubCallback/GitHubCallback.tsx +++ b/src/pages/OAuthCallback/OAuthCallback.tsx @@ -1,14 +1,23 @@ import { useEffect, useState } from 'react'; -import { useNavigate, useSearchParams } from 'react-router-dom'; +import { useNavigate, useSearchParams, useLocation } from 'react-router-dom'; import { Icon } from '@iconify/react'; import authService from '../../services/authService'; -import './GitHubCallback.css'; +import './OAuthCallback.css'; -export default function GitHubCallback() { +interface OAuthCallbackProps { + provider?: 'github' | 'gitee'; +} + +export default function OAuthCallback({ provider: propProvider }: OAuthCallbackProps) { const navigate = useNavigate(); + const location = useLocation(); const [searchParams] = useSearchParams(); const [error, setError] = useState(''); + // Determine provider from prop or path + const provider = propProvider || (location.pathname.includes('gitee') ? 'gitee' : 'github'); + const providerName = provider === 'github' ? 'GitHub' : 'Gitee'; + useEffect(() => { const handleCallback = async () => { const errorParam = searchParams.get('error'); @@ -16,7 +25,7 @@ export default function GitHubCallback() { const refreshToken = searchParams.get('refresh_token'); if (errorParam) { - setError('GitHub 授权失败'); + setError(`${providerName} 授权失败`); setTimeout(() => navigate('/login'), 2000); return; } @@ -41,20 +50,24 @@ export default function GitHubCallback() { } try { - await authService.handleGitHubCallback(code); + if (provider === 'gitee') { + await authService.handleGiteeCallback(code); + } else { + await authService.handleGitHubCallback(code); + } navigate('/home'); } catch (err) { - setError(err instanceof Error ? err.message : 'GitHub 登录失败'); + setError(err instanceof Error ? err.message : `${providerName} 登录失败`); setTimeout(() => navigate('/login'), 2000); } }; handleCallback(); - }, [searchParams, navigate]); + }, [searchParams, navigate, provider, providerName]); return ( -
-
+
+
{error ? ( <> @@ -65,7 +78,7 @@ export default function GitHubCallback() { ) : ( <> -

正在处理 GitHub 登录

+

正在处理 {providerName} 登录

请稍候...

)} diff --git a/src/pages/OAuthCallback/index.ts b/src/pages/OAuthCallback/index.ts new file mode 100644 index 0000000..3bec5e8 --- /dev/null +++ b/src/pages/OAuthCallback/index.ts @@ -0,0 +1 @@ +export { default } from './OAuthCallback'; diff --git a/src/router/index.tsx b/src/router/index.tsx index 8202cdb..d9e33ba 100644 --- a/src/router/index.tsx +++ b/src/router/index.tsx @@ -14,7 +14,7 @@ import LoanCalculatorPage from '../pages/LoanCalculatorPage'; import TaxCalculatorPage from '../pages/TaxCalculatorPage'; import Login from '../pages/Login/Login'; import Profile from '../pages/Profile'; -import GitHubCallback from '../pages/GitHubCallback'; +import OAuthCallback from '../pages/OAuthCallback/OAuthCallback'; import Notifications from '../pages/Notifications'; import Layout from '../components/common/Layout'; import ProtectedRoute from '../components/common/ProtectedRoute'; @@ -34,7 +34,11 @@ export const router = createBrowserRouter([ }, { path: '/auth/github/callback', - element: , + element: , + }, + { + path: '/auth/gitee/callback', + element: , }, { path: '/', diff --git a/src/services/authService.ts b/src/services/authService.ts index 09c02a1..6ce4339 100644 --- a/src/services/authService.ts +++ b/src/services/authService.ts @@ -178,6 +178,50 @@ export async function handleGitHubCallback(code: string): Promise<{ user: User; throw new Error('GitHub authentication failed'); } +/** + * Get Gitee OAuth login URL + */ +export function getGiteeLoginUrl(state?: string): string { + // 强制修正:如果不是本地开发环境,必须使用相对路径 + const isLocal = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; + const baseUrl = isLocal + ? (import.meta.env.VITE_API_BASE_URL || 'http://localhost:2612/api/v1') + : '/api/v1'; + + // 处理相对路径问题:URL构造函数依然需要完整的 base 才能处理相对路径 + let fullUrlString; + if (baseUrl.startsWith('/')) { + fullUrlString = `${window.location.origin}${baseUrl}/auth/gitee`; + } else { + fullUrlString = `${baseUrl}/auth/gitee`; + } + + const url = new URL(fullUrlString); + if (state) { + url.searchParams.append('state', state); + } + return url.toString(); +} + +/** + * Redirect to Gitee OAuth login + */ +export function loginWithGitee(state?: string): void { + window.location.href = getGiteeLoginUrl(state); +} + +/** + * Handle Gitee OAuth callback + */ +export async function handleGiteeCallback(code: string): Promise<{ user: User; tokens: TokenPair }> { + const response = await api.get('/auth/gitee/callback', { code }); + if (response.success && response.data) { + setTokens(response.data.tokens); + return response.data; + } + throw new Error('Gitee authentication failed'); +} + /** * Get current user information */ @@ -215,6 +259,9 @@ export default { loginWithGitHub, getGitHubLoginUrl, handleGitHubCallback, + loginWithGitee, + getGiteeLoginUrl, + handleGiteeCallback, getCurrentUser, updatePassword, };