Browse Source

更新移动端认证API,新增地理位置参数支持,优化登录逻辑以处理位置获取失败的情况,提升用户体验和代码可维护性。

zyh 8 months ago
parent
commit
52c4e2d187
5 changed files with 44 additions and 10 deletions
  1. 8 3
      client/mobile/api.ts
  2. 2 2
      client/mobile/hooks.tsx
  3. 29 2
      client/mobile/pages_login.tsx
  4. 1 1
      client/share/types.ts
  5. 4 2
      server/routes_auth.ts

+ 8 - 3
client/mobile/api.ts

@@ -40,7 +40,7 @@ interface AuthResponse {
 
 
 // 定义Auth API接口类型
 // 定义Auth API接口类型
 interface AuthAPIType {
 interface AuthAPIType {
-  login: (username: string, password: string) => Promise<AuthLoginResponse>;
+  login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<AuthLoginResponse>;
   register: (username: string, email: string, password: string) => Promise<AuthResponse>;
   register: (username: string, email: string, password: string) => Promise<AuthResponse>;
   logout: () => Promise<AuthResponse>;
   logout: () => Promise<AuthResponse>;
   getCurrentUser: () => Promise<User>;
   getCurrentUser: () => Promise<User>;
@@ -54,9 +54,14 @@ interface AuthAPIType {
 // Auth相关API
 // Auth相关API
 export const AuthAPI: AuthAPIType = {
 export const AuthAPI: AuthAPIType = {
   // 登录API
   // 登录API
-  login: async (username: string, password: string) => {
+  login: async (username: string, password: string, latitude?: number, longitude?: number) => {
     try {
     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;
       return response.data;
     } catch (error) {
     } catch (error) {
       throw error;
       throw error;

+ 2 - 2
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 {
     try {
-      const response = await AuthAPI.login(username, password);
+      const response = await AuthAPI.login(username, password, latitude, longitude);
       const { token, user } = response;
       const { token, user } = response;
       
       
       // 保存到状态和本地存储
       // 保存到状态和本地存储

+ 29 - 2
client/mobile/pages_login.tsx

@@ -25,10 +25,37 @@ const LoginPage: React.FC = () => {
     setError(null);
     setError(null);
     
     
     try {
     try {
-      await login(username, password);
+      // 获取地理位置
+      const position = await new Promise<GeolocationPosition>((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('/');
       navigate('/');
     } catch (err) {
     } 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 {
     } finally {
       setLoading(false);
       setLoading(false);
     }
     }

+ 1 - 1
client/share/types.ts

@@ -48,7 +48,7 @@ export interface MenuItem {
 export interface AuthContextType {
 export interface AuthContextType {
   user: User | null;
   user: User | null;
   token: string | null;
   token: string | null;
-  login: (username: string, password: string) => Promise<void>;
+  login: (username: string, password: string, latitude?: number, longitude?: number) => Promise<void>;
   logout: () => Promise<void>;
   logout: () => Promise<void>;
   isAuthenticated: boolean;
   isAuthenticated: boolean;
   isLoading: boolean;
   isLoading: boolean;

+ 4 - 2
server/routes_auth.ts

@@ -54,7 +54,7 @@ export function createAuthRoutes(withAuth: WithAuth) {
   authRoutes.post('/login', async (c) => {
   authRoutes.post('/login', async (c) => {
     try {
     try {
       const auth = c.get('auth')
       const auth = c.get('auth')
-      const { username, password } = await c.req.json()
+      const { username, password, latitude, longitude } = await c.req.json()
       
       
       if (!username || !password) {
       if (!username || !password) {
         return c.json({ error: '用户名和密码不能为空' }, 400)
         return c.json({ error: '用户名和密码不能为空' }, 400)
@@ -69,7 +69,9 @@ export function createAuthRoutes(withAuth: WithAuth) {
             user_id: result.user.id,
             user_id: result.user.id,
             login_time: apiClient.database.fn.now(),
             login_time: apiClient.database.fn.now(),
             ip_address: c.req.header('x-forwarded-for') || '未知',
             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
           })
           })
         }
         }