| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- import { useState } from 'react'
- import { View, Text, ScrollView } from '@tarojs/components'
- import Taro from '@tarojs/taro'
- import { TabBarLayout } from '@/layouts/tab-bar-layout'
- import { useAuth } from '@/utils/auth'
- import { cn } from '@/utils/cn'
- import { Button } from '@/components/ui/button'
- import { Navbar } from '@/components/ui/navbar'
- import { AvatarUpload } from '@/components/ui/avatar-upload'
- import { type UploadResult } from '@/utils/minio'
- import './index.css'
- const ProfilePage: React.FC = () => {
- const { user: userProfile, logout, isLoading: loading, updateUser } = useAuth()
- const [updatingAvatar, setUpdatingAvatar] = useState(false)
- const handleLogout = async () => {
- try {
- Taro.showModal({
- title: '退出登录',
- content: '确定要退出登录吗?',
- success: async (res) => {
- if (res.confirm) {
- Taro.showLoading({ title: '退出中...' })
- await logout()
- Taro.hideLoading()
- Taro.showToast({
- title: '已退出登录',
- icon: 'success',
- duration: 1500
- })
- setTimeout(() => {
- Taro.reLaunch({ url: '/pages/index/index' })
- }, 1500)
- }
- }
- })
- } catch (error) {
- Taro.hideLoading()
- Taro.showToast({
- title: '退出失败,请重试',
- icon: 'none'
- })
- }
- }
- const handleAvatarUpload = async (result: UploadResult) => {
- try {
- setUpdatingAvatar(true)
- Taro.showLoading({ title: '更新头像...' })
-
- // 这里应该调用更新用户头像的API
- // 假设有一个更新用户信息的API
- console.log('头像上传成功:', result)
-
- // 更新本地用户数据
- if (userProfile) {
- const updatedUser = {
- ...userProfile,
- avatarFileId: result.fileId
- }
- updateUser(updatedUser)
- }
-
- Taro.hideLoading()
- Taro.showToast({
- title: '头像更新成功',
- icon: 'success'
- })
- } catch (error) {
- console.error('更新头像失败:', error)
- Taro.hideLoading()
- Taro.showToast({
- title: '更新头像失败',
- icon: 'none'
- })
- } finally {
- setUpdatingAvatar(false)
- }
- }
- const handleAvatarUploadError = (error: Error) => {
- console.error('头像上传失败:', error)
- Taro.showToast({
- title: '上传失败,请重试',
- icon: 'none'
- })
- }
- const handleEditProfile = () => {
- Taro.showToast({
- title: '功能开发中...',
- icon: 'none'
- })
- }
- const handleSettings = () => {
- Taro.showToast({
- title: '功能开发中...',
- icon: 'none'
- })
- }
- const menuItems = [
- {
- icon: 'i-heroicons-user-circle-20-solid',
- title: '编辑资料',
- onClick: handleEditProfile,
- color: 'text-blue-500'
- },
- {
- icon: 'i-heroicons-users-20-solid',
- title: '乘车人管理',
- onClick: () => Taro.navigateTo({ url: '/pages/passengers/passengers' }),
- color: 'text-orange-500'
- },
- {
- icon: 'i-heroicons-cog-6-tooth-20-solid',
- title: '设置',
- onClick: handleSettings,
- color: 'text-gray-500'
- },
- {
- icon: 'i-heroicons-shield-check-20-solid',
- title: '隐私政策',
- onClick: () => Taro.showToast({ title: '功能开发中...', icon: 'none' }),
- color: 'text-green-500'
- },
- {
- icon: 'i-heroicons-question-mark-circle-20-solid',
- title: '帮助与反馈',
- onClick: () => Taro.showToast({ title: '功能开发中...', icon: 'none' }),
- color: 'text-purple-500'
- }
- ]
- if (loading) {
- return (
- <TabBarLayout activeKey="profile">
- <View className="flex-1 flex items-center justify-center">
- <View className="i-heroicons-arrow-path-20-solid animate-spin w-8 h-8 text-blue-500" />
- </View>
- </TabBarLayout>
- )
- }
- if (!userProfile) {
- return (
- <TabBarLayout activeKey="profile">
- <Navbar
- title="个人中心"
- leftIcon=""
- />
- <View className="flex-1 flex flex-col items-center justify-center">
- <View className="flex flex-col items-center">
- <View className="i-heroicons-exclamation-circle-20-solid w-12 h-12 text-gray-400 mx-auto mb-4" />
- <Text className="text-gray-600 mb-4">请先登录</Text>
- <Button
- variant="default"
- size="lg"
- onClick={() => Taro.navigateTo({ url: '/pages/login/index' })}
- >
- 去登录
- </Button>
- </View>
- </View>
- </TabBarLayout>
- )
- }
- return (
- <TabBarLayout activeKey="profile">
- <Navbar
- title="个人中心"
- rightIcon="i-heroicons-cog-6-tooth-20-solid"
- onClickRight={handleSettings}
- leftIcon=""
- backgroundColor="bg-primary"
- textColor="text-white"
- border={false}
- />
- <ScrollView className="flex-1 bg-[#F8F9FA] pb-10">
- {/* 用户信息区域 - 渐变背景 */}
- <View className="bg-gradient-to-br from-[#4A90C2] to-[#357ABD] p-[40rpx_32rpx_32rpx_32rpx] text-white">
- <View className="flex items-center">
- <View className="relative mr-[32rpx]">
- <AvatarUpload
- currentAvatar={userProfile.avatarFile?.fullUrl}
- onUploadSuccess={handleAvatarUpload}
- onUploadError={handleAvatarUploadError}
- size={100}
- editable={!updatingAvatar}
- className="border-3 border-white/30"
- />
- </View>
- <View className="flex-1">
- <Text className="text-[32rpx] font-bold text-white">{userProfile.username}</Text>
- <Text className="text-[22rpx] opacity-80 mt-1">
- ID: {String(userProfile.id).slice(-4)}
- </Text>
- </View>
- </View>
- </View>
- {/* 会员信息卡片 */}
- <View className="m-[24rpx_32rpx] hidden">
- <View
- className="bg-gradient-to-br from-[#667eea] to-[#764ba2] rounded-[20rpx] p-[24rpx] text-white shadow-[0_6rpx_24rpx_rgba(102,126,234,0.3)]"
- onClick={() => Taro.showToast({ title: '会员功能开发中...', icon: 'none' })}
- >
- <View className="flex justify-between items-center mb-[20rpx]">
- <View className="flex items-center">
- <View className="i-heroicons-star-20-solid text-[32rpx] mr-[10rpx]" />
- <Text className="text-[32rpx] font-bold">普通会员</Text>
- </View>
- <View className="text-[28rpx] opacity-80">{'>'}</View>
- </View>
- <View className="flex justify-around">
- <View className="text-center">
- <Text className="text-[32rpx] font-bold block mb-[6rpx]">0</Text>
- <Text className="text-[22rpx] opacity-80">积分</Text>
- </View>
- <View className="text-center">
- <Text className="text-[32rpx] font-bold block mb-[6rpx]">¥0</Text>
- <Text className="text-[22rpx] opacity-80">累计消费</Text>
- </View>
- </View>
- {/* 会员进度条 */}
- <View className="bg-white/10 rounded-[16rpx] p-[20rpx] mt-[20rpx]">
- <Text className="text-[24rpx] opacity-90 mb-[12rpx] text-center">
- 距离升级还需消费 ¥1000
- </Text>
- <View className="h-[8rpx] bg-white/20 rounded-[4rpx] overflow-hidden">
- <View
- className="h-full bg-gradient-to-r from-[#FFD700] to-[#FFA500] rounded-[4rpx] transition-all duration-300"
- style={{ width: '30%' }}
- />
- </View>
- </View>
- </View>
- </View>
- {/* 功能菜单 */}
- <View className="m-[24rpx_32rpx]">
- <Text className="text-[30rpx] font-bold text-[#333] mb-[20rpx]">我的服务</Text>
- <View className="bg-white rounded-[20rpx] shadow-[0_4rpx_20rpx_rgba(0,0,0,0.08)] border border-[#E5E5EA] overflow-hidden">
- {menuItems.map((item, index) => (
- <View
- key={index}
- className="flex items-center p-[28rpx_32rpx] border-b-2 border-[#E5E5EA] active:bg-[#F8F9FA] transition-colors duration-300"
- onClick={item.onClick}
- >
- <View className={cn("w-6 h-6 mr-3", item.color, item.icon)} />
- <View className="flex-1 ml-0">
- <Text className="text-[30rpx] font-bold text-[#333] block">{item.title}</Text>
- <Text className="text-[24rpx] text-[#666] mt-[6rpx]">
- {item.title === '编辑资料' && '修改个人信息'}
- {item.title === '乘车人管理' && '管理乘车人信息'}
- {item.title === '设置' && '应用设置'}
- {item.title === '隐私政策' && '查看隐私政策'}
- {item.title === '帮助与反馈' && '获取帮助和反馈'}
- </Text>
- </View>
- <View className="text-[28rpx] text-[#ccc] font-bold">{'>'}</View>
- </View>
- ))}
- </View>
- </View>
- {/* 客服与帮助区域 */}
- <View className="m-[24rpx_32rpx]">
- <Text className="text-[30rpx] font-bold text-[#333] mb-[20rpx]">客服与帮助</Text>
- <View className="bg-white rounded-[20rpx] shadow-[0_4rpx_20rpx_rgba(0,0,0,0.08)] border border-[#E5E5EA] overflow-hidden">
- {[
- { title: '联系客服', desc: '7x24小时在线客服', icon: 'i-heroicons-phone-20-solid', color: 'text-blue-500' },
- { title: '常见问题', desc: '查看常见问题解答', icon: 'i-heroicons-question-mark-circle-20-solid', color: 'text-green-500' },
- { title: '意见反馈', desc: '提出宝贵意见', icon: 'i-heroicons-chat-bubble-left-ellipsis-20-solid', color: 'text-orange-500' }
- ].map((item, index) => (
- <View
- key={index}
- className="flex items-center p-[28rpx_32rpx] border-b-2 border-[#E5E5EA] active:bg-[#F8F9FA] transition-colors duration-300"
- onClick={() => Taro.showToast({ title: `${item.title}功能开发中...`, icon: 'none' })}
- >
- <View className={cn("w-6 h-6 mr-3", item.color, item.icon)} />
- <View className="flex-1 ml-0">
- <Text className="text-[30rpx] font-bold text-[#333] block">{item.title}</Text>
- <Text className="text-[24rpx] text-[#666]">{item.desc}</Text>
- </View>
- <View className="text-[28rpx] text-[#ccc] font-bold">{'>'}</View>
- </View>
- ))}
- </View>
- </View>
- {/* 退出登录按钮 */}
- <View className="m-[24rpx_32rpx]">
- <View className="bg-white rounded-[20rpx] shadow-[0_4rpx_20rpx_rgba(0,0,0,0.08)] border border-[#E5E5EA] overflow-hidden">
- <View
- className="flex items-center justify-center p-[28rpx_32rpx] active:bg-[#F8F9FA] transition-colors duration-300"
- onClick={handleLogout}
- >
- <View className="i-heroicons-arrow-left-on-rectangle-20-solid w-6 h-6 text-red-500 mr-3" />
- <Text className="text-[30rpx] font-bold text-red-500">退出登录</Text>
- </View>
- </View>
- </View>
- {/* 版本信息 */}
- <View className="text-center py-[32rpx]">
- <Text className="text-[22rpx] text-[#999]">去看出行 v1.0.0</Text>
- </View>
- </ScrollView>
- </TabBarLayout>
- )
- }
- export default ProfilePage
|