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,121 @@
import React from 'react'
import { View, Text } from '@tarojs/components'
import type { ShopUserAddress } from '@/api/shop/shopUserAddress/model'
interface AddressCardProps {
address: ShopUserAddress
/** 是否选中状态(用于选择地址场景,如结算页) */
selected?: boolean
/** 是否为选择模式显示radio圆圈 */
selectMode?: boolean
onClick?: () => void
showActions?: boolean
onEdit?: () => void
onDelete?: () => void
onDefault?: () => void
}
const AddressCard: React.FC<AddressCardProps> = ({
address,
selected = false,
selectMode = false,
onClick,
showActions = false,
onEdit,
onDelete,
onDefault,
}) => {
const fullAddress = [address.province, address.city, address.region, address.address].filter(Boolean).join(' ')
return (
<View
className={`bg-white rounded-xl p-3 mb-3 border-2 ${selected ? 'border-green-500' : 'border-transparent'}`}
style={{
boxShadow: '0 1px 4px rgba(0,0,0,0.06)',
}}
onClick={onClick}
>
<View className="flex gap-3">
{/* 选择模式下的radio圈 */}
{selectMode && (
<View className="flex items-center justify-center" style={{ minWidth: '20px' }}>
<View
className={`rounded-full ${selected ? 'bg-green-500' : 'border-2 border-gray-300'}`}
style={{ width: '18px', height: '18px' }}
>
{selected && (
<View className="flex items-center justify-center h-full">
<Text className="text-white text-xs" style={{ fontSize: '10px', lineHeight: '18px' }}></Text>
</View>
)}
</View>
</View>
)}
<View className="flex-1">
{/* 姓名 + 手机号 + 默认标签 */}
<View className="flex items-center gap-2 mb-1">
<Text className="text-sm font-medium text-gray-800">{address.name}</Text>
<Text className="text-sm text-gray-600">{address.phone}</Text>
{address.isDefault && (
<View className="bg-green-50 rounded px-1 py-0">
<Text className="text-green-600" style={{ fontSize: '10px' }}></Text>
</View>
)}
</View>
{/* 完整地址 */}
<Text className="text-xs text-gray-500 leading-5">
{fullAddress || address.fullAddress || address.address || '暂无地址'}
</Text>
</View>
</View>
{/* 操作栏 */}
{showActions && (
<View className="flex justify-between items-center mt-2 pt-2 border-t border-gray-100">
{/* 默认地址切换 */}
<View
className="flex items-center gap-1"
onClick={(e) => { e.stopPropagation(); onDefault?.() }}
>
<View
className={`rounded-full ${address.isDefault ? 'bg-green-500' : 'border-2 border-gray-300'}`}
style={{ width: '16px', height: '16px' }}
>
{address.isDefault && (
<View className="flex items-center justify-center h-full">
<Text className="text-white" style={{ fontSize: '9px', lineHeight: '16px' }}></Text>
</View>
)}
</View>
<Text className={`text-xs ${address.isDefault ? 'text-green-600' : 'text-gray-400'}`}></Text>
</View>
{/* 编辑/删除 */}
<View className="flex items-center gap-3">
{onEdit && (
<Text
className="text-xs text-gray-400"
onClick={(e) => { e.stopPropagation(); onEdit?.() }}
>
</Text>
)}
<Text className="text-xs text-gray-200">|</Text>
{onDelete && (
<Text
className="text-xs text-gray-400"
onClick={(e) => { e.stopPropagation(); onDelete?.() }}
>
</Text>
)}
</View>
</View>
)}
</View>
)
}
export default AddressCard