Bläddra i källkod

重构用户个人信息页面,将个人信息组件移至独立文件,整合用户信息获取与更新功能,优化表单处理逻辑,提升用户体验和代码可维护性。

zyh 8 månader sedan
förälder
incheckning
a9d6794cb7
2 ändrade filer med 128 tillägg och 110 borttagningar
  1. 1 66
      client/mobile/mobile_app.tsx
  2. 127 44
      client/mobile/pages_profile.tsx

+ 1 - 66
client/mobile/mobile_app.tsx

@@ -191,72 +191,7 @@ const ErrorPage = () => {
   );
 };
 
-// 添加个人页面组件
-const ProfilePage = () => {
-  const { logout, user } = useAuth();
-  const navigate = useNavigate();
-
-  const handleLogout = async () => {
-    if (confirm('确定要退出登录吗?')) {
-      await logout();
-      navigate('/mobile/login');
-    }
-  };
-
-  return (
-    <div className="p-4">
-      <h1 className="text-2xl font-bold mb-4">我的</h1>
-      <div className="bg-white rounded-lg shadow p-4 mb-4">
-        <div className="flex items-center mb-4">
-          <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mr-4">
-            {user?.avatar ? (
-              <img
-                src={user.avatar}
-                alt={user?.nickname || user?.username || '用户'}
-                className="w-16 h-16 rounded-full object-cover"
-              />
-            ) : (
-              <span className="text-2xl text-blue-600">用户</span>
-            )}
-          </div>
-          <div>
-            <h2 className="text-xl font-semibold">{user?.nickname || user?.username || '未登录用户'}</h2>
-            <p className="text-gray-500">个人信息</p>
-          </div>
-        </div>
-      </div>
-      <div className="bg-white rounded-lg shadow mb-4">
-        <div className="p-4 border-b">
-          <span className="font-medium">设置</span>
-        </div>
-        <div className="divide-y">
-          <div className="p-4 flex justify-between items-center">
-            <span>账号安全</span>
-            <span className="text-gray-400">›</span>
-          </div>
-          <div className="p-4 flex justify-between items-center">
-            <span>通知设置</span>
-            <span className="text-gray-400">›</span>
-          </div>
-          <div className="p-4 flex justify-between items-center">
-            <span>隐私</span>
-            <span className="text-gray-400">›</span>
-          </div>
-          <div className="p-4 flex justify-between items-center">
-            <span>关于</span>
-            <span className="text-gray-400">›</span>
-          </div>
-        </div>
-      </div>
-      <button
-        onClick={handleLogout}
-        className="w-full py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
-      >
-        退出登录
-      </button>
-    </div>
-  );
-};
+import ProfilePage from './pages_profile.tsx'
 
 // 移动端布局组件 - 包含底部导航
 const MobileLayout = () => {

+ 127 - 44
client/mobile/pages_profile.tsx

@@ -1,63 +1,114 @@
 import React from 'react'
 import { useNavigate } from 'react-router'
 import { useForm } from 'react-hook-form'
+import { useQuery, useMutation } from '@tanstack/react-query'
 import { UserAPI } from './api.ts'
 import type { User } from '../share/types.ts'
+import { useAuth } from './hooks.tsx'
 
 export default function ProfilePage() {
   const navigate = useNavigate()
-  const { register, handleSubmit, formState: { errors }, setValue } = useForm<Omit<User, 'id' | 'role' | 'avatar'> & { password?: string }>()
-  const [loading, setLoading] = React.useState(false)
-  const [user, setUser] = React.useState<User | null>(null)
+  const { register, handleSubmit, formState: { errors }, setValue } = useForm<{
+    username: string
+    nickname: string
+    email: string
+    phone?: string
+    password?: string
+  }>()
 
   // 获取当前用户信息
-  React.useEffect(() => {
-    const fetchUser = async () => {
-      try {
-        const res = await UserAPI.getUsers({ limit: 1 })
-        if (res.data?.length > 0) {
-          const userData = res.data[0]
-          setUser(userData)
-          setValue('username', userData.username)
-          setValue('nickname', userData.nickname)
-          setValue('email', userData.email)
-          setValue('phone', userData.phone)
-        }
-      } catch (error) {
-        console.error('获取用户信息失败:', error)
+  const { data: user } = useQuery({
+    queryKey: ['currentUser'],
+    queryFn: async () => {
+      const res = await UserAPI.getUsers({ limit: 1 })
+      if (res.data?.length > 0) {
+        const userData = res.data[0]
+        setValue('username', userData.username)
+        setValue('nickname', userData.nickname || '')
+        setValue('email', userData.email || '')
+        setValue('phone', userData.phone || '')
+        return userData
       }
+      return null
     }
-    fetchUser()
-  }, [setValue])
+  })
 
-  // 提交表单更新用户信息
-  const onSubmit = async (data: User) => {
-    try {
-      setLoading(true)
-      if (!user?.id) return
-      
-      const updatedUser = await UserAPI.updateUser(user.id, {
-        nickname: data.nickname,
-        email: data.email,
-        phone: data.phone,
-        ...(data.password ? { password: data.password } : {})
-      })
-      
-      setUser(updatedUser.data)
-      alert('更新成功')
-    } catch (error) {
-      console.error('更新失败:', error)
-      alert('更新失败')
-    } finally {
-      setLoading(false)
+  
+    // 更新用户信息
+    const { mutate: updateUser, isPending } = useMutation({
+      mutationFn: async (data: {
+        nickname: string
+        email: string
+        phone?: string
+        password?: string
+      }) => {
+        if (!user?.id) throw new Error('用户ID不存在')
+        return UserAPI.updateUser(user.id, {
+          nickname: data.nickname,
+          email: data.email,
+          phone: data.phone,
+          ...(data.password ? { password: data.password } : {})
+        })
+      },
+      onSuccess: (updatedUser) => {
+        alert('更新成功')
+      },
+      onError: (error) => {
+        console.error('更新失败:', error)
+        alert('更新失败')
+      }
+    })
+
+  const onSubmit = (data: {
+    username: string
+    nickname: string
+    email: string
+    phone?: string
+    password?: string
+  }) => {
+    updateUser({
+      nickname: data.nickname,
+      email: data.email,
+      phone: data.phone,
+      password: data.password
+    })
+  }
+
+  const { logout } = useAuth()
+
+  const handleLogout = async () => {
+    if (confirm('确定要退出登录吗?')) {
+      await logout()
+      navigate('/mobile/login')
     }
   }
 
   return (
-    <div className="p-4 max-w-md mx-auto">
-      <h1 className="text-2xl font-bold mb-6 text-gray-800">个人信息</h1>
+    <div className="p-4">
+      <h1 className="text-2xl font-bold mb-4">我的</h1>
+      <div className="bg-white rounded-lg shadow p-4 mb-4">
+        <div className="flex items-center mb-4">
+          <div className="w-16 h-16 bg-blue-100 rounded-full flex items-center justify-center mr-4">
+            {user?.avatar ? (
+              <img
+                src={user.avatar}
+                alt={user?.nickname || user?.username || '用户'}
+                className="w-16 h-16 rounded-full object-cover"
+              />
+            ) : (
+              <span className="text-2xl text-blue-600">用户</span>
+            )}
+          </div>
+          <div>
+            <h2 className="text-xl font-semibold">{user?.nickname || user?.username || '未登录用户'}</h2>
+            <p className="text-gray-500">个人信息</p>
+          </div>
+        </div>
+      </div>
       
-      <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
+      <div className="bg-white rounded-lg shadow p-4 mb-4">
+        <h2 className="text-lg font-semibold mb-4">编辑信息</h2>
+        <form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
         <div>
           <label className="block text-sm font-medium text-gray-700 mb-1">用户名</label>
           <input
@@ -113,10 +164,10 @@ export default function ProfilePage() {
         <div className="flex space-x-3 pt-4">
           <button
             type="submit"
-            disabled={loading}
+            disabled={isPending}
             className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50"
           >
-            {loading ? '保存中...' : '保存'}
+            {isPending ? '保存中...' : '保存'}
           </button>
           <button
             type="button"
@@ -127,6 +178,38 @@ export default function ProfilePage() {
           </button>
         </div>
       </form>
+      </div>
+      
+      <div className="bg-white rounded-lg shadow mb-4">
+        <div className="p-4 border-b">
+          <span className="font-medium">设置</span>
+        </div>
+        <div className="divide-y">
+          <div className="p-4 flex justify-between items-center">
+            <span>账号安全</span>
+            <span className="text-gray-400">›</span>
+          </div>
+          <div className="p-4 flex justify-between items-center">
+            <span>通知设置</span>
+            <span className="text-gray-400">›</span>
+          </div>
+          <div className="p-4 flex justify-between items-center">
+            <span>隐私</span>
+            <span className="text-gray-400">›</span>
+          </div>
+          <div className="p-4 flex justify-between items-center">
+            <span>关于</span>
+            <span className="text-gray-400">›</span>
+          </div>
+        </div>
+      </div>
+      
+      <button
+        onClick={handleLogout}
+        className="w-full py-3 bg-red-600 text-white rounded-lg hover:bg-red-700 transition-colors"
+      >
+        退出登录
+      </button>
     </div>
   )
 }