From 52c4e2d187fcf5757f4d2d7616c9f277a0540d40 Mon Sep 17 00:00:00 2001 From: zyh Date: Thu, 10 Apr 2025 06:55:47 +0000 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E7=A7=BB=E5=8A=A8=E7=AB=AF?= =?UTF-8?q?=E8=AE=A4=E8=AF=81API=EF=BC=8C=E6=96=B0=E5=A2=9E=E5=9C=B0?= =?UTF-8?q?=E7=90=86=E4=BD=8D=E7=BD=AE=E5=8F=82=E6=95=B0=E6=94=AF=E6=8C=81?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E7=99=BB=E5=BD=95=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E4=BB=A5=E5=A4=84=E7=90=86=E4=BD=8D=E7=BD=AE=E8=8E=B7=E5=8F=96?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E7=9A=84=E6=83=85=E5=86=B5=EF=BC=8C=E6=8F=90?= =?UTF-8?q?=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93=E9=AA=8C=E5=92=8C=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=8F=AF=E7=BB=B4=E6=8A=A4=E6=80=A7=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/mobile/api.ts | 11 ++++++++--- client/mobile/hooks.tsx | 4 ++-- client/mobile/pages_login.tsx | 31 +++++++++++++++++++++++++++++-- client/share/types.ts | 2 +- server/routes_auth.ts | 6 ++++-- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/client/mobile/api.ts b/client/mobile/api.ts index 08dee14..c6ff6d1 100644 --- a/client/mobile/api.ts +++ b/client/mobile/api.ts @@ -40,7 +40,7 @@ interface AuthResponse { // 定义Auth API接口类型 interface AuthAPIType { - login: (username: string, password: string) => Promise; + login: (username: string, password: string, latitude?: number, longitude?: number) => Promise; register: (username: string, email: string, password: string) => Promise; logout: () => Promise; getCurrentUser: () => Promise; @@ -54,9 +54,14 @@ interface AuthAPIType { // Auth相关API export const AuthAPI: AuthAPIType = { // 登录API - login: async (username: string, password: string) => { + login: async (username: string, password: string, latitude?: number, longitude?: number) => { try { - const response = await axios.post(`${API_BASE_URL}/auth/login`, { username, password }); + const response = await axios.post(`${API_BASE_URL}/auth/login`, { + username, + password, + latitude, + longitude + }); return response.data; } catch (error) { throw error; diff --git a/client/mobile/hooks.tsx b/client/mobile/hooks.tsx index cb0b021..9b4e1ee 100644 --- a/client/mobile/hooks.tsx +++ b/client/mobile/hooks.tsx @@ -63,9 +63,9 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({ children // 登录函数 - const login = async (username: string, password: string) => { + const login = async (username: string, password: string, latitude?: number, longitude?: number) => { try { - const response = await AuthAPI.login(username, password); + const response = await AuthAPI.login(username, password, latitude, longitude); const { token, user } = response; // 保存到状态和本地存储 diff --git a/client/mobile/pages_login.tsx b/client/mobile/pages_login.tsx index d10b33c..ade9ac8 100644 --- a/client/mobile/pages_login.tsx +++ b/client/mobile/pages_login.tsx @@ -25,10 +25,37 @@ const LoginPage: React.FC = () => { setError(null); try { - await login(username, password); + // 获取地理位置 + const position = await new Promise((resolve, reject) => { + if (!navigator.geolocation) { + reject(new Error('浏览器不支持地理位置功能')); + return; + } + + navigator.geolocation.getCurrentPosition( + resolve, + (err) => reject(new Error(`获取位置失败: ${err.message}`)), + { timeout: 5000 } + ); + }); + + const { latitude, longitude } = position.coords; + await login(username, password, latitude, longitude); navigate('/'); } catch (err) { - setError(handleApiError(err)); + // 如果获取位置失败,仍然允许登录但不带位置信息 + const error = err instanceof Error ? err : new Error(String(err)); + if (error.message.includes('获取位置失败')) { + console.warn('获取位置失败:', err); + try { + await login(username, password); + navigate('/'); + } catch (loginErr) { + setError(handleApiError(loginErr)); + } + } else { + setError(handleApiError(err)); + } } finally { setLoading(false); } diff --git a/client/share/types.ts b/client/share/types.ts index a9349c5..9f42d02 100644 --- a/client/share/types.ts +++ b/client/share/types.ts @@ -48,7 +48,7 @@ export interface MenuItem { export interface AuthContextType { user: User | null; token: string | null; - login: (username: string, password: string) => Promise; + login: (username: string, password: string, latitude?: number, longitude?: number) => Promise; logout: () => Promise; isAuthenticated: boolean; isLoading: boolean; diff --git a/server/routes_auth.ts b/server/routes_auth.ts index 0051422..edb23fa 100644 --- a/server/routes_auth.ts +++ b/server/routes_auth.ts @@ -54,7 +54,7 @@ export function createAuthRoutes(withAuth: WithAuth) { authRoutes.post('/login', async (c) => { try { const auth = c.get('auth') - const { username, password } = await c.req.json() + const { username, password, latitude, longitude } = await c.req.json() if (!username || !password) { return c.json({ error: '用户名和密码不能为空' }, 400) @@ -69,7 +69,9 @@ export function createAuthRoutes(withAuth: WithAuth) { user_id: result.user.id, login_time: apiClient.database.fn.now(), ip_address: c.req.header('x-forwarded-for') || '未知', - user_agent: c.req.header('user-agent') || '未知' + user_agent: c.req.header('user-agent') || '未知', + latitude: latitude || null, + longitude: longitude || null }) }