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

This commit is contained in:
zyh
2025-04-10 13:31:12 +00:00
parent 1977a6757d
commit a9d6794cb7
2 changed files with 128 additions and 110 deletions

View File

@@ -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 = () => {

View File

@@ -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>
)
}