import React, { useState, useEffect } from 'react' import { View, Text, ScrollView } from '@tarojs/components' import Taro from '@tarojs/taro' import { useUser } from '@/hooks/useUser' import { useScrollHeight } from '@/hooks/useScrollHeight' import { listCouponCenter } from '@/api/shop/shopCoupon' import { takeCoupon } from '@/api/shop/shopUserCoupon' import type { ShopCouponWithTake } from '@/api/shop/shopCoupon/model' import EmptyState from '@/components/common/EmptyState' definePageConfig({ navigationBarTitleText: '领券中心', }) const CouponCenterPage: React.FC = () => { const { isLoggedIn } = useUser() const [coupons, setCoupons] = useState([]) const [loading, setLoading] = useState(true) const [claiming, setClaiming] = useState(null) const scrollHeight = useScrollHeight(44) useEffect(() => { if (!isLoggedIn) { Taro.navigateTo({ url: '/passport/login' }) return } fetchCoupons() }, [isLoggedIn]) const fetchCoupons = async () => { setLoading(true) try { const data = await listCouponCenter({ status: 0, isExpire: 0 }) setCoupons(data || []) } catch (e) { console.error('获取优惠券失败:', e) } finally { setLoading(false) } } const handleClaimCoupon = async (id: number) => { if (claiming) return setClaiming(id) try { await takeCoupon(id) Taro.showToast({ title: '领取成功', icon: 'success' }) // 更新本地状态,避免重新请求 setCoupons(prev => prev.map(c => c.id === id ? { ...c, hasTake: true, userTakeNum: (c.userTakeNum || 0) + 1 } : c) ) } catch (e: any) { Taro.showToast({ title: e?.message || '领取失败', icon: 'none' }) } finally { setClaiming(null) } } const getCouponValueText = (item: ShopCouponWithTake) => { switch (item.type) { case 20: return `${item.discount}折` case 40: return `¥${item.reducePrice}` case 50: return item.useCount && item.useCount > 0 ? `${item.useCount}次` : '不限次' default: return `¥${item.reducePrice}` } } const getCouponConditionText = (item: ShopCouponWithTake) => { if (item.type === 40) return '无门槛' if (item.type === 50) { const parts: string[] = [] if (item.venueType !== undefined && item.venueType !== null) parts.push(`场地类型${item.venueType}`) if (item.useDuration && item.useDuration > 0) parts.push(`${item.useDuration}分钟`) return parts.length > 0 ? parts.join(' | ') : '场地使用' } if (item.minPrice && Number(item.minPrice) > 0) return `满${item.minPrice}可用` return '无门槛' } const getCouponExpireText = (item: ShopCouponWithTake) => { if (item.expireType === 10) return `领取后${item.expireDay}天内有效` if (item.endTime) return `有效期至:${item.endTime.slice(0, 10)}` return '' } const getCouponTypeText = (type?: number) => { const map: Record = { 10: '满减券', 20: '折扣券', 30: '免费券', 40: '无门槛券', 50: '场地使用券' } return map[type || 0] || '优惠券' } const isClaimable = (item: ShopCouponWithTake) => { if (item.hasTake) return false if (item.limitPerUser !== -1 && (item.userTakeNum || 0) >= (item.limitPerUser || 1)) return false if (item.totalCount !== -1 && (item.issuedCount || 0) >= (item.totalCount || 0)) return false return true } if (!isLoggedIn) return null return ( {loading ? ( 加载中... ) : coupons.length === 0 ? ( ) : ( {coupons.map((item) => { const canClaim = isClaimable(item) return ( {getCouponValueText(item)} {getCouponConditionText(item)} {getCouponTypeText(item.type)} {item.name} {getCouponExpireText(item)} canClaim && handleClaimCoupon(item.id!)} > {claiming === item.id ? '领取中' : item.hasTake ? '已领取' : '领取'} ) })} )} ) } export default CouponCenterPage