feat(user): 新增收货地址管理及售后申请页面

- 新增地址类型定义,增强前端地址数据结构
- 新增地址编辑页面,支持地址智能识别和定位选点功能
- 地址编辑支持省市区选择及默认地址设置
- 新增地址列表页面,支持地址展示、删除、编辑和选择功能
- 实现售后申请页面,支持选择售后类型和退款原因
- 售后申请支持商品选择、退款金额计算和凭证上传
- 新增售后详情页面,支持售后状态展示及申请取消
- 优化页面加载和用户交互体验,增加错误提示和权限处理
This commit is contained in:
2026-07-01 12:11:56 +08:00
parent bf6ed504cc
commit 1fa58040f3
636 changed files with 58878 additions and 716 deletions

View File

@@ -0,0 +1,5 @@
export default {
navigationBarTitleText: '会员升级',
navigationBarBackgroundColor: '#667eea',
navigationBarTextStyle: 'white',
}

View File

@@ -0,0 +1,261 @@
import React, { useState, useEffect } from 'react'
import { View, Text, ScrollView, Image } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useUser } from '@/hooks/useUser'
import { useScrollHeight } from '@/hooks/useScrollHeight'
import { useRequest } from '@/hooks/useRequest'
import { getDealerSetting } from '@/api/shop/shopMemberCenter'
import MemberBadge from '@/components/business/MemberBadge'
definePageConfig({
navigationBarTitleText: '会员升级',
})
interface LevelInfo {
id: number
levelName: string
levelIcon: string
upgradeCondition: string
upgradeAmount: number
commissionRate: number
selfBuyRate: number
}
const MemberUpgradePage: React.FC = () => {
const { user, isLoggedIn } = useUser()
const scrollHeight = useScrollHeight()
const [currentLevel, setCurrentLevel] = useState(0)
// 获取会员等级列表
const { data: levelList, run: runLevelList, loading } = useRequest(getDealerSetting, {
manual: true,
})
useEffect(() => {
if (!isLoggedIn) {
Taro.navigateTo({ url: '/passport/login' })
return
}
runLevelList()
}, [isLoggedIn])
// 处理升级
const handleUpgrade = (level: LevelInfo) => {
Taro.showModal({
title: '升级确认',
content: `确定升级为${level.levelName}吗?升级后将享受更多权益。`,
success: (res) => {
if (res.confirm) {
Taro.showToast({
title: '升级功能开发中',
icon: 'none',
})
}
},
})
}
// 当前等级信息
const currentLevelName = user?.memberLevelName || '普通会员'
const currentLevelIndex = levelList?.findIndex(l => l.levelName === currentLevelName) || 0
// 会员等级图标映射
const levelIcons: Record<string, string> = {
'普通会员': '👤',
'白银会员': '🥈',
'黄金会员': '🥇',
'铂金会员': '💎',
'钻石会员': '💠',
'黑金会员': '🏆',
}
// 获取图标
const getLevelIcon = (name: string) => levelIcons[name] || '⭐'
if (!isLoggedIn) {
return null
}
return (
<View className='min-h-screen bg-gray-50'>
<ScrollView scrollY style={{ height: scrollHeight }}>
{/* 顶部背景 */}
<View className='p-5 pb-8 rounded-b-3xl'
style={{ background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }}>
<View className='flex items-center justify-center flex-col'>
<View className='w-20 h-20 rounded-full bg-white bg-opacity-20 flex items-center justify-center mb-3'>
<Text className='text-4xl'>{getLevelIcon(currentLevelName)}</Text>
</View>
<Text className='text-white text-lg font-bold'></Text>
<View className='mt-2'>
<MemberBadge levelName={currentLevelName} />
</View>
</View>
</View>
{/* 升级说明 */}
<View className='mx-3 -mt-4 bg-white rounded-xl p-4 shadow-sm'>
<View className='flex items-start gap-3'>
<View className='w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center flex-shrink-0'>
<Text className='text-base'>💡</Text>
</View>
<View className='flex-1'>
<Text className='text-gray-800 text-sm font-medium block'></Text>
<Text className='text-gray-500 text-xs mt-1 block leading-relaxed'>
</Text>
</View>
</View>
</View>
{/* 会员等级列表 */}
<View className='mx-3 mt-3'>
<Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
{loading ? (
<View className='flex items-center justify-center py-10'>
<Text className='text-gray-400'>...</Text>
</View>
) : !levelList || levelList.length === 0 ? (
<View className='bg-white rounded-xl p-6 text-center'>
<Text className='text-gray-400'></Text>
<Text className='text-gray-400 text-xs mt-2'></Text>
</View>
) : (
<View className='space-y-3'>
{levelList.map((level, idx) => {
const isCurrent = level.levelName === currentLevelName
const isHigher = idx > currentLevelIndex
return (
<View
key={level.id}
className={`bg-white rounded-xl p-4 ${isHigher ? 'border-2 border-dashed border-orange-300' : ''}`}
>
<View className='flex items-start gap-3'>
{/* 等级图标 */}
<View className={`w-12 h-12 rounded-xl flex items-center justify-center ${
idx === 0 ? 'bg-gray-100' :
idx === 1 ? 'bg-orange-100' :
idx === 2 ? 'bg-yellow-100' :
idx === 3 ? 'bg-blue-100' :
idx === 4 ? 'bg-purple-100' : 'bg-pink-100'
}`}>
<Text className='text-2xl'>{getLevelIcon(level.levelName)}</Text>
</View>
{/* 等级信息 */}
<View className='flex-1'>
<View className='flex items-center gap-2'>
<Text className='text-gray-800 font-medium'>{level.levelName}</Text>
{isCurrent && (
<View className='px-2 py-0.5 bg-green-100 rounded-full'>
<Text className='text-green-600 text-xs'></Text>
</View>
)}
{isHigher && (
<View className='px-2 py-0.5 bg-orange-100 rounded-full'>
<Text className='text-orange-600 text-xs'></Text>
</View>
)}
</View>
{/* 佣金比例 */}
<View className='flex gap-4 mt-2'>
<View>
<Text className='text-gray-500 text-xs'></Text>
<Text className='text-orange-500 font-bold'>{(level.commissionRate * 100).toFixed(1)}%</Text>
</View>
<View>
<Text className='text-gray-500 text-xs'></Text>
<Text className='text-green-500 font-bold'>{(level.selfBuyRate * 100).toFixed(1)}%</Text>
</View>
</View>
{/* 升级条件 */}
{level.upgradeCondition && (
<Text className='text-gray-400 text-xs mt-2'>{level.upgradeCondition}</Text>
)}
</View>
{/* 升级按钮 */}
{isHigher && (
<View
className='px-4 py-2 bg-orange-500 rounded-full'
onClick={() => handleUpgrade(level)}
>
<Text className='text-white text-sm'></Text>
</View>
)}
</View>
</View>
)
})}
</View>
)}
</View>
{/* 权益对比 */}
<View className='mx-3 mt-4'>
<Text className='text-base font-medium text-gray-800 mb-3 block'></Text>
<View className='bg-white rounded-xl overflow-hidden'>
<View className='flex bg-gray-50'>
<View className='flex-1 px-3 py-2'>
<Text className='text-gray-500 text-xs text-center'></Text>
</View>
{['普通会员', '白银会员', '黄金会员'].map(name => (
<View key={name} className='flex-1 px-2 py-2'>
<Text className='text-gray-500 text-xs text-center'>{name}</Text>
</View>
))}
</View>
{[
{ label: '购物折扣', values: ['9.5折', '9折', '8.5折'] },
{ label: '团队佣金', values: ['5%', '10%', '15%'] },
{ label: '自购返利', values: ['1%', '3%', '5%'] },
{ label: '专属客服', values: ['❌', '✔', '✔'] },
{ label: '优先发货', values: ['❌', '❌', '✔'] },
].map((row, idx) => (
<View
key={row.label}
className={`flex ${idx % 2 === 0 ? 'bg-white' : 'bg-gray-50'}`}
>
<View className='flex-1 px-3 py-3'>
<Text className='text-gray-700 text-sm text-center'>{row.label}</Text>
</View>
{row.values.map((val, vIdx) => (
<View key={vIdx} className='flex-1 px-2 py-3'>
<Text className={`text-sm text-center ${
val === '❌' ? 'text-gray-300' :
val === '✔' ? 'text-green-500' : 'text-gray-700'
}`}>{val}</Text>
</View>
))}
</View>
))}
</View>
</View>
{/* 联系客服 */}
<View className='mx-3 mt-4 mb-4'>
<View
className='bg-white rounded-xl p-4 flex items-center justify-between'
onClick={() => Taro.navigateTo({ url: '/pages/user/customer-service/index' })}
>
<View className='flex items-center gap-3'>
<View className='w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center'>
<Text className='text-lg'>📞</Text>
</View>
<View>
<Text className='text-gray-800 font-medium block'></Text>
<Text className='text-gray-400 text-xs mt-0.5'></Text>
</View>
</View>
<Text className='text-gray-300'></Text>
</View>
</View>
</ScrollView>
</View>
)
}
export default MemberUpgradePage