|
@@ -8,11 +8,18 @@ import { Button } from '@/components/ui/button'
|
|
|
import { Navbar } from '@/components/ui/navbar'
|
|
import { Navbar } from '@/components/ui/navbar'
|
|
|
import { AvatarUpload } from '@/components/ui/avatar-upload'
|
|
import { AvatarUpload } from '@/components/ui/avatar-upload'
|
|
|
import { type UploadResult } from '@/utils/minio'
|
|
import { type UploadResult } from '@/utils/minio'
|
|
|
|
|
+import TDesignUserCenterCard from '@/components/tdesign/user-center-card'
|
|
|
|
|
+import TDesignOrderGroup from '@/components/tdesign/order-group'
|
|
|
|
|
+import TDesignCellGroup from '@/components/tdesign/cell-group'
|
|
|
|
|
+import TDesignCell from '@/components/tdesign/cell'
|
|
|
|
|
+import TDesignPopup from '@/components/tdesign/popup'
|
|
|
|
|
+import TDesignIcon from '@/components/tdesign/icon'
|
|
|
import './index.css'
|
|
import './index.css'
|
|
|
|
|
|
|
|
const ProfilePage: React.FC = () => {
|
|
const ProfilePage: React.FC = () => {
|
|
|
const { user: userProfile, logout, isLoading: loading, updateUser } = useAuth()
|
|
const { user: userProfile, logout, isLoading: loading, updateUser } = useAuth()
|
|
|
const [updatingAvatar, setUpdatingAvatar] = useState(false)
|
|
const [updatingAvatar, setUpdatingAvatar] = useState(false)
|
|
|
|
|
+ const [showCustomerService, setShowCustomerService] = useState(false)
|
|
|
|
|
|
|
|
const handleLogout = async () => {
|
|
const handleLogout = async () => {
|
|
|
try {
|
|
try {
|
|
@@ -101,39 +108,59 @@ const ProfilePage: React.FC = () => {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- const menuItems = [
|
|
|
|
|
- {
|
|
|
|
|
- icon: 'i-heroicons-shopping-bag-20-solid',
|
|
|
|
|
- title: '我的订单',
|
|
|
|
|
- onClick: () => Taro.navigateTo({ url: '/pages/order-list/index' }),
|
|
|
|
|
- color: 'text-orange-500'
|
|
|
|
|
- },
|
|
|
|
|
- {
|
|
|
|
|
- icon: 'i-heroicons-user-circle-20-solid',
|
|
|
|
|
- title: '编辑资料',
|
|
|
|
|
- onClick: handleEditProfile,
|
|
|
|
|
- color: 'text-blue-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'
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ const handleCustomerService = () => {
|
|
|
|
|
+ setShowCustomerService(true)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handleCloseCustomerService = () => {
|
|
|
|
|
+ setShowCustomerService(false)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handleCallCustomerService = () => {
|
|
|
|
|
+ Taro.makePhoneCall({
|
|
|
|
|
+ phoneNumber: '400-123-4567'
|
|
|
|
|
+ })
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 订单状态数据
|
|
|
|
|
+ const orderTagInfos = [
|
|
|
|
|
+ { title: '待付款', iconName: 'clock', orderNum: 0 },
|
|
|
|
|
+ { title: '待发货', iconName: 'package', orderNum: 0 },
|
|
|
|
|
+ { title: '待收货', iconName: 'truck', orderNum: 0 },
|
|
|
|
|
+ { title: '待评价', iconName: 'star', orderNum: 0 }
|
|
|
]
|
|
]
|
|
|
|
|
|
|
|
|
|
+ // 菜单数据 - 按照 tcb-shop-demo 的结构
|
|
|
|
|
+ const menuData = [
|
|
|
|
|
+ [
|
|
|
|
|
+ { title: '收货地址', icon: 'location', type: 'address' },
|
|
|
|
|
+ { title: '联系客服', icon: 'service', type: 'service' }
|
|
|
|
|
+ ],
|
|
|
|
|
+ [
|
|
|
|
|
+ { title: '关于我们', icon: 'info-circle', type: 'about' },
|
|
|
|
|
+ { title: '隐私政策', icon: 'shield-check', type: 'privacy' }
|
|
|
|
|
+ ]
|
|
|
|
|
+ ]
|
|
|
|
|
+
|
|
|
|
|
+ const handleCellClick = (type: string) => {
|
|
|
|
|
+ switch (type) {
|
|
|
|
|
+ case 'address':
|
|
|
|
|
+ Taro.showToast({ title: '收货地址功能开发中...', icon: 'none' })
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'service':
|
|
|
|
|
+ handleCustomerService()
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'about':
|
|
|
|
|
+ Taro.showToast({ title: '关于我们功能开发中...', icon: 'none' })
|
|
|
|
|
+ break
|
|
|
|
|
+ case 'privacy':
|
|
|
|
|
+ Taro.showToast({ title: '隐私政策功能开发中...', icon: 'none' })
|
|
|
|
|
+ break
|
|
|
|
|
+ default:
|
|
|
|
|
+ Taro.showToast({ title: '功能开发中...', icon: 'none' })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (loading) {
|
|
if (loading) {
|
|
|
return (
|
|
return (
|
|
|
<TabBarLayout activeKey="profile">
|
|
<TabBarLayout activeKey="profile">
|
|
@@ -170,92 +197,52 @@ const ProfilePage: React.FC = () => {
|
|
|
|
|
|
|
|
return (
|
|
return (
|
|
|
<TabBarLayout activeKey="profile">
|
|
<TabBarLayout activeKey="profile">
|
|
|
- <Navbar
|
|
|
|
|
- title="个人中心"
|
|
|
|
|
- rightIcon="i-heroicons-cog-6-tooth-20-solid"
|
|
|
|
|
- onClickRight={handleSettings}
|
|
|
|
|
- leftIcon=""
|
|
|
|
|
|
|
+ {/* 用户中心卡片 - 使用固定定位 */}
|
|
|
|
|
+ <TDesignUserCenterCard
|
|
|
|
|
+ avatar={userProfile.avatarFile?.fullUrl}
|
|
|
|
|
+ nickname={userProfile.username}
|
|
|
|
|
+ isLoggedIn={!!userProfile}
|
|
|
|
|
+ onUserEdit={handleEditProfile}
|
|
|
|
|
+ className="tdesign-user-center-card-profile"
|
|
|
/>
|
|
/>
|
|
|
- <ScrollView className="flex-1 bg-gray-50">
|
|
|
|
|
- {/* 用户信息卡片 */}
|
|
|
|
|
- <View className="bg-white rounded-b-3xl shadow-sm pb-8">
|
|
|
|
|
- <View className="flex flex-col items-center pt-8 pb-6">
|
|
|
|
|
- <View className="relative">
|
|
|
|
|
- <AvatarUpload
|
|
|
|
|
- currentAvatar={userProfile.avatarFile?.fullUrl}
|
|
|
|
|
- onUploadSuccess={handleAvatarUpload}
|
|
|
|
|
- onUploadError={handleAvatarUploadError}
|
|
|
|
|
- size={96}
|
|
|
|
|
- editable={!updatingAvatar}
|
|
|
|
|
- />
|
|
|
|
|
- </View>
|
|
|
|
|
- <Text className="text-xl font-bold text-gray-900 mt-4">{userProfile.username}</Text>
|
|
|
|
|
- {userProfile.email && (
|
|
|
|
|
- <Text className="text-sm text-gray-600 mt-1">{userProfile.email}</Text>
|
|
|
|
|
- )}
|
|
|
|
|
- <View className="flex items-center mt-2">
|
|
|
|
|
- <View className="i-heroicons-calendar-20-solid w-4 h-4 text-gray-400 mr-1" />
|
|
|
|
|
- <Text className="text-xs text-gray-500">
|
|
|
|
|
- 注册于 {new Date(userProfile.createdAt).toLocaleDateString('zh-CN')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
|
|
|
|
|
- {/* 统计信息 */}
|
|
|
|
|
- <View className="px-6">
|
|
|
|
|
- <View className="grid grid-cols-3 gap-4 text-center">
|
|
|
|
|
- <View className="bg-gray-50 rounded-xl p-4">
|
|
|
|
|
- <Text className="text-2xl font-bold text-blue-500">0</Text>
|
|
|
|
|
- <Text className="text-xs text-gray-600 mt-1">收藏</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- <View className="bg-gray-50 rounded-xl p-4">
|
|
|
|
|
- <Text className="text-2xl font-bold text-green-500">0</Text>
|
|
|
|
|
- <Text className="text-xs text-gray-600 mt-1">点赞</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- <View className="bg-gray-50 rounded-xl p-4">
|
|
|
|
|
- <Text className="text-2xl font-bold text-purple-500">0</Text>
|
|
|
|
|
- <Text className="text-xs text-gray-600 mt-1">关注</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
|
|
+ {/* 内容区域 - 使用 margin-top 定位 */}
|
|
|
|
|
+ <ScrollView className="flex-1 bg-gray-50 tdesign-user-center-content">
|
|
|
|
|
+ {/* 订单状态卡片 */}
|
|
|
|
|
+ <View className="px-4 pt-4">
|
|
|
|
|
+ <TDesignOrderGroup
|
|
|
|
|
+ orderTagInfos={orderTagInfos}
|
|
|
|
|
+ title="我的订单"
|
|
|
|
|
+ desc="全部订单"
|
|
|
|
|
+ onTopClick={() => Taro.showToast({ title: '查看全部订单', icon: 'none' })}
|
|
|
|
|
+ onItemClick={(item) => Taro.showToast({ title: `查看${item.title}订单`, icon: 'none' })}
|
|
|
|
|
+ />
|
|
|
</View>
|
|
</View>
|
|
|
|
|
|
|
|
{/* 功能菜单 */}
|
|
{/* 功能菜单 */}
|
|
|
- <View className="px-4 pt-6">
|
|
|
|
|
- <View className="bg-white rounded-2xl shadow-sm overflow-hidden">
|
|
|
|
|
- {menuItems.map((item, index) => (
|
|
|
|
|
- <View
|
|
|
|
|
- key={index}
|
|
|
|
|
- className="flex items-center px-4 py-4 active:bg-gray-50 transition-colors duration-150"
|
|
|
|
|
- onClick={item.onClick}
|
|
|
|
|
- >
|
|
|
|
|
- <View className={cn("w-6 h-6 mr-3", item.color, item.icon)} />
|
|
|
|
|
- <Text className="flex-1 text-gray-800">{item.title}</Text>
|
|
|
|
|
- <View className="i-heroicons-chevron-right-20-solid w-5 h-5 text-gray-400" />
|
|
|
|
|
- </View>
|
|
|
|
|
- ))}
|
|
|
|
|
- </View>
|
|
|
|
|
- </View>
|
|
|
|
|
-
|
|
|
|
|
- {/* 账号信息 */}
|
|
|
|
|
- <View className="px-4 pt-6">
|
|
|
|
|
- <View className="bg-white rounded-2xl shadow-sm p-4">
|
|
|
|
|
- <Text className="text-sm font-medium text-gray-700 mb-3">账号信息</Text>
|
|
|
|
|
- <View className="space-y-3">
|
|
|
|
|
- <View className="flex justify-between items-center">
|
|
|
|
|
- <Text className="text-sm text-gray-600">用户ID</Text>
|
|
|
|
|
- <Text className="text-sm text-gray-900 font-mono">{userProfile.id}</Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- {userProfile.updatedAt && (
|
|
|
|
|
- <View className="flex justify-between items-center">
|
|
|
|
|
- <Text className="text-sm text-gray-600">最近登录</Text>
|
|
|
|
|
- <Text className="text-sm text-gray-900">
|
|
|
|
|
- {new Date(userProfile.updatedAt).toLocaleString('zh-CN')}
|
|
|
|
|
- </Text>
|
|
|
|
|
- </View>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ <View className="px-4 pt-4">
|
|
|
|
|
+ {menuData.map((group, groupIndex) => (
|
|
|
|
|
+ <View key={groupIndex} className="mb-4">
|
|
|
|
|
+ <TDesignCellGroup>
|
|
|
|
|
+ {group.map((item, itemIndex) => (
|
|
|
|
|
+ <TDesignCell
|
|
|
|
|
+ key={itemIndex}
|
|
|
|
|
+ title={item.title}
|
|
|
|
|
+ arrow
|
|
|
|
|
+ bordered={itemIndex < group.length - 1}
|
|
|
|
|
+ onClick={() => handleCellClick(item.type)}
|
|
|
|
|
+ noteSlot={
|
|
|
|
|
+ <TDesignIcon
|
|
|
|
|
+ name={item.icon}
|
|
|
|
|
+ size="48rpx"
|
|
|
|
|
+ color="#6a6a6a"
|
|
|
|
|
+ />
|
|
|
|
|
+ }
|
|
|
|
|
+ />
|
|
|
|
|
+ ))}
|
|
|
|
|
+ </TDesignCellGroup>
|
|
|
</View>
|
|
</View>
|
|
|
- </View>
|
|
|
|
|
|
|
+ ))}
|
|
|
</View>
|
|
</View>
|
|
|
|
|
|
|
|
{/* 退出登录按钮 */}
|
|
{/* 退出登录按钮 */}
|
|
@@ -280,6 +267,38 @@ const ProfilePage: React.FC = () => {
|
|
|
</Text>
|
|
</Text>
|
|
|
</View>
|
|
</View>
|
|
|
</ScrollView>
|
|
</ScrollView>
|
|
|
|
|
+
|
|
|
|
|
+ {/* 客服弹窗 */}
|
|
|
|
|
+ <TDesignPopup
|
|
|
|
|
+ visible={showCustomerService}
|
|
|
|
|
+ placement="bottom"
|
|
|
|
|
+ onVisibleChange={(visible) => setShowCustomerService(visible)}
|
|
|
|
|
+ onClose={handleCloseCustomerService}
|
|
|
|
|
+ >
|
|
|
|
|
+ <View className="popup-content">
|
|
|
|
|
+ <View className="popup-title border-bottom-1px">
|
|
|
|
|
+ 服务时间: 9:00-18:00
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <View
|
|
|
|
|
+ className="popup-phone border-bottom-1px"
|
|
|
|
|
+ onClick={handleCallCustomerService}
|
|
|
|
|
+ >
|
|
|
|
|
+ 电话客服
|
|
|
|
|
+ </View>
|
|
|
|
|
+ <button
|
|
|
|
|
+ className="popup-phone border-bottom-1px online"
|
|
|
|
|
+ open-type="contact"
|
|
|
|
|
+ >
|
|
|
|
|
+ 在线客服
|
|
|
|
|
+ </button>
|
|
|
|
|
+ <View
|
|
|
|
|
+ className="popup-close"
|
|
|
|
|
+ onClick={handleCloseCustomerService}
|
|
|
|
|
+ >
|
|
|
|
|
+ 取消
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </View>
|
|
|
|
|
+ </TDesignPopup>
|
|
|
</TabBarLayout>
|
|
</TabBarLayout>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|