feat(user): 新增收货地址管理及售后申请页面
- 新增地址类型定义,增强前端地址数据结构 - 新增地址编辑页面,支持地址智能识别和定位选点功能 - 地址编辑支持省市区选择及默认地址设置 - 新增地址列表页面,支持地址展示、删除、编辑和选择功能 - 实现售后申请页面,支持选择售后类型和退款原因 - 售后申请支持商品选择、退款金额计算和凭证上传 - 新增售后详情页面,支持售后状态展示及申请取消 - 优化页面加载和用户交互体验,增加错误提示和权限处理
This commit is contained in:
185
src_bak/components/business/CouponSelect/index.tsx
Normal file
185
src_bak/components/business/CouponSelect/index.tsx
Normal file
@@ -0,0 +1,185 @@
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import { View, Text, ScrollView } from '@tarojs/components'
|
||||
import type { ShopUserCoupon } from '@/api/shop/shopUserCoupon/model'
|
||||
|
||||
interface CouponSelectProps {
|
||||
visible: boolean
|
||||
coupons: ShopUserCoupon[]
|
||||
minAmount?: number
|
||||
selectedCouponId?: string
|
||||
onClose: () => void
|
||||
onSelect: (coupon: ShopUserCoupon | null) => void
|
||||
}
|
||||
|
||||
const CouponSelect: React.FC<CouponSelectProps> = ({
|
||||
visible,
|
||||
coupons,
|
||||
minAmount = 0,
|
||||
selectedCouponId,
|
||||
onClose,
|
||||
onSelect,
|
||||
}) => {
|
||||
const [showOverlay, setShowOverlay] = React.useState(false)
|
||||
const [slideUp, setSlideUp] = React.useState(false)
|
||||
|
||||
// 控制动画
|
||||
React.useEffect(() => {
|
||||
if (visible) {
|
||||
setShowOverlay(true)
|
||||
setTimeout(() => setSlideUp(true), 10)
|
||||
} else {
|
||||
setSlideUp(false)
|
||||
setTimeout(() => setShowOverlay(false), 300)
|
||||
}
|
||||
}, [visible])
|
||||
|
||||
const handleClose = () => {
|
||||
setSlideUp(false)
|
||||
setTimeout(() => {
|
||||
setShowOverlay(false)
|
||||
onClose()
|
||||
}, 300)
|
||||
}
|
||||
|
||||
const handleSelect = (coupon: ShopUserCoupon | null) => {
|
||||
handleClose()
|
||||
onSelect(coupon)
|
||||
}
|
||||
|
||||
const availableCoupons = useMemo(() => {
|
||||
return coupons.filter(c => {
|
||||
if (c.status !== 0 && c.status !== undefined) return false
|
||||
if (c.endTime && new Date(c.endTime) < new Date()) return false
|
||||
return (Number(c.minPrice) || 0) <= minAmount
|
||||
})
|
||||
}, [coupons, minAmount])
|
||||
|
||||
if (!showOverlay) return null
|
||||
|
||||
return (
|
||||
<View className='coupon-select-overlay'>
|
||||
{/* 遮罩层 */}
|
||||
<View
|
||||
className={`absolute inset-0 bg-black/50 z-50 ${slideUp ? 'opacity-100' : 'opacity-0'}`}
|
||||
onClick={handleClose}
|
||||
/>
|
||||
|
||||
{/* 弹窗内容 */}
|
||||
<View
|
||||
className={`absolute bottom-0 left-0 right-0 bg-white rounded-t-2xl z-50 ${slideUp ? '' : 'hidden'}`}
|
||||
style={{ maxHeight: '60vh' }}
|
||||
>
|
||||
<View className='p-4'>
|
||||
{/* 关闭按钮 */}
|
||||
<View className='flex justify-end mb-2'>
|
||||
<View
|
||||
className='w-6 h-6 rounded-full bg-gray-100 flex items-center justify-center'
|
||||
onClick={handleClose}
|
||||
>
|
||||
<Text className='text-gray-400 text-sm'>×</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<View className='flex justify-between items-center mb-4'>
|
||||
<Text className='text-base font-medium'>选择优惠券</Text>
|
||||
<Text
|
||||
className='text-sm text-green-600'
|
||||
onClick={() => handleSelect(null)}
|
||||
>
|
||||
不使用优惠券
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{availableCoupons.length === 0 ? (
|
||||
<View className='py-8 text-center'>
|
||||
<Text className='text-sm text-gray-400'>暂无可用优惠券</Text>
|
||||
</View>
|
||||
) : (
|
||||
<ScrollView scrollY style={{ maxHeight: '50vh' }}>
|
||||
{availableCoupons.map((coupon) => {
|
||||
const isSelected = selectedCouponId === coupon.id
|
||||
return (
|
||||
<View
|
||||
key={coupon.id}
|
||||
className='flex rounded-lg border mb-2 overflow-hidden'
|
||||
style={{
|
||||
borderColor: isSelected ? (
|
||||
coupon.type === 40 ? '#3b82f6' :
|
||||
coupon.type === 50 ? '#06b6d4' :
|
||||
'#0e932e'
|
||||
) : '#f0f0f0',
|
||||
backgroundColor: isSelected ? (
|
||||
coupon.type === 40 ? '#eff6ff' :
|
||||
coupon.type === 50 ? '#ecfeff' :
|
||||
'#f0fdf4'
|
||||
) : '#fff',
|
||||
}}
|
||||
onClick={() => handleSelect(coupon)}
|
||||
>
|
||||
<View className='w-24 flex flex-col items-center justify-center py-3' style={{
|
||||
backgroundColor: coupon.type === 40 ? '#eff6ff' :
|
||||
coupon.type === 50 ? '#ecfeff' :
|
||||
'#f0fdf4'
|
||||
}}>
|
||||
{coupon.type === 20 ? (
|
||||
<View className='text-center'>
|
||||
<Text className='text-lg font-bold text-green-600 block'>
|
||||
{coupon.discount || 0}折
|
||||
</Text>
|
||||
<Text className='text-xs text-gray-500'>
|
||||
{coupon.minPrice && Number(coupon.minPrice) > 0 ? `满${coupon.minPrice}可用` : '无门槛'}
|
||||
</Text>
|
||||
</View>
|
||||
) : coupon.type === 50 ? (
|
||||
<View className='text-center'>
|
||||
<Text className='text-lg font-bold text-teal-600 block'>
|
||||
{coupon.useCount && coupon.useCount > 0 ? `${coupon.useCount}次` : '不限次'}
|
||||
</Text>
|
||||
<Text className='text-xs text-gray-500'>
|
||||
{coupon.useDuration && coupon.useDuration > 0 ? `${coupon.useDuration}分钟` : '场地使用'}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View className='text-center'>
|
||||
<Text className='text-xs font-medium block' style={{
|
||||
color: coupon.type === 40 ? '#3b82f6' : '#16a34a'
|
||||
}}>¥</Text>
|
||||
<Text className='text-xl font-bold block' style={{
|
||||
color: coupon.type === 40 ? '#3b82f6' : '#16a34a'
|
||||
}}>
|
||||
{coupon.reducePrice || 0}
|
||||
</Text>
|
||||
<Text className='text-xs text-gray-500'>
|
||||
{coupon.type === 40 ? '无门槛' :
|
||||
(coupon.minPrice && Number(coupon.minPrice) > 0 ? `满${coupon.minPrice}可用` : '无门槛')}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View className='flex-1 p-3 flex flex-col justify-between'>
|
||||
<Text className='text-sm text-gray-800 font-medium'>
|
||||
{coupon.name || coupon.description || '优惠券'}
|
||||
</Text>
|
||||
<Text className='text-xs text-gray-400'>
|
||||
{coupon.startTime?.slice(0, 10)} ~ {coupon.endTime?.slice(0, 10)}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{isSelected && (
|
||||
<View className='flex items-center pr-3'>
|
||||
<Text className='text-green-500 text-lg'>{'✓'}</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
})}
|
||||
</ScrollView>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default CouponSelect
|
||||
Reference in New Issue
Block a user