docs: 更新优惠券相关文档- 新增优惠券API集成文档

- 新增优惠券卡片对齐修复文档
- 新增优惠券状态显示调试文档
- 新增优惠券组件警告修复文档- 更新用ShopInfo Hook字段迁移文档
- 更新Arguments关键字修复文档
This commit is contained in:
2025-08-15 01:52:36 +08:00
parent dc87f644c9
commit 1b24a611a8
50 changed files with 6530 additions and 595 deletions

View File

@@ -26,6 +26,16 @@ import {PaymentHandler, PaymentType, buildSingleGoodsOrder} from "@/utils/paymen
import OrderConfirmSkeleton from "@/components/OrderConfirmSkeleton";
import CouponList from "@/components/CouponList";
import {CouponCardProps} from "@/components/CouponCard";
import {getMyAvailableCoupons} from "@/api/shop/shopUserCoupon";
import {
transformCouponData,
calculateCouponDiscount,
isCouponUsable,
getCouponUnusableReason,
sortCoupons,
filterUsableCoupons,
filterUnusableCoupons
} from "@/utils/couponUtils";
const OrderConfirm = () => {
@@ -53,38 +63,8 @@ const OrderConfirm = () => {
// 优惠券相关状态
const [selectedCoupon, setSelectedCoupon] = useState<CouponCardProps | null>(null)
const [couponVisible, setCouponVisible] = useState<boolean>(false)
const [availableCoupons] = useState<CouponCardProps[]>([
{
amount: 5,
minAmount: 20,
type: 1,
status: 0,
title: '满20减5',
startTime: '2024-01-01',
endTime: '2024-12-31',
theme: 'red'
},
{
amount: 10,
minAmount: 50,
type: 1,
status: 0,
title: '满50减10',
startTime: '2024-01-01',
endTime: '2024-12-31',
theme: 'orange'
},
{
amount: 20,
minAmount: 100,
type: 1,
status: 0,
title: '满100减20',
startTime: '2024-01-01',
endTime: '2024-12-31',
theme: 'blue'
}
])
const [availableCoupons, setAvailableCoupons] = useState<CouponCardProps[]>([])
const [couponLoading, setCouponLoading] = useState<boolean>(false)
const router = Taro.getCurrentInstance().router;
const goodsId = router?.params?.goodsId;
@@ -99,22 +79,7 @@ const OrderConfirm = () => {
const getCouponDiscount = () => {
if (!selectedCoupon || !goods) return 0
const total = getGoodsTotal()
// 检查是否满足使用条件
if (selectedCoupon.minAmount && total < selectedCoupon.minAmount) {
return 0
}
switch (selectedCoupon.type) {
case 1: // 满减券
return selectedCoupon.amount
case 2: // 折扣券
return total * (1 - selectedCoupon.amount / 10)
case 3: // 免费券
return total
default:
return 0
}
return calculateCouponDiscount(selectedCoupon, total)
}
// 计算实付金额
@@ -133,17 +98,35 @@ const OrderConfirm = () => {
// 处理数量变化
const handleQuantityChange = (value: string | number) => {
const newQuantity = typeof value === 'string' ? parseInt(value) || 1 : value
setQuantity(Math.max(1, Math.min(newQuantity, goods?.stock || 999)))
const finalQuantity = Math.max(1, Math.min(newQuantity, goods?.stock || 999))
setQuantity(finalQuantity)
// 数量变化时,重新排序优惠券并检查当前选中的优惠券是否还可用
if (availableCoupons.length > 0) {
const newTotal = parseFloat(goods?.price || '0') * finalQuantity
const sortedCoupons = sortCoupons(availableCoupons, newTotal)
setAvailableCoupons(sortedCoupons)
// 检查当前选中的优惠券是否还可用
if (selectedCoupon && !isCouponUsable(selectedCoupon, newTotal)) {
setSelectedCoupon(null)
Taro.showToast({
title: '当前优惠券不满足使用条件,已自动取消',
icon: 'none'
})
}
}
}
// 处理优惠券选择
const handleCouponSelect = (coupon: CouponCardProps) => {
const total = getGoodsTotal()
// 检查是否满足使用条件
if (coupon.minAmount && total < coupon.minAmount) {
// 检查是否可用
if (!isCouponUsable(coupon, total)) {
const reason = getCouponUnusableReason(coupon, total)
Taro.showToast({
title: `需满${coupon.minAmount}元才能使用此优惠券`,
title: reason || '优惠券不可用',
icon: 'none'
})
return
@@ -166,6 +149,45 @@ const OrderConfirm = () => {
})
}
// 加载用户优惠券
const loadUserCoupons = async () => {
try {
setCouponLoading(true)
// 使用新的API获取可用优惠券
const res = await getMyAvailableCoupons()
if (res && res.length > 0) {
// 转换数据格式
const transformedCoupons = res.map(transformCouponData)
// 按优惠金额排序
const total = getGoodsTotal()
const sortedCoupons = sortCoupons(transformedCoupons, total)
setAvailableCoupons(sortedCoupons)
console.log('加载优惠券成功:', {
originalData: res,
transformedData: transformedCoupons,
sortedData: sortedCoupons
})
} else {
setAvailableCoupons([])
console.log('暂无可用优惠券')
}
} catch (error) {
console.error('加载优惠券失败:', error)
setAvailableCoupons([])
Taro.showToast({
title: '加载优惠券失败',
icon: 'none'
})
} finally {
setCouponLoading(false)
}
}
/**
* 统一支付入口
*/
@@ -208,7 +230,7 @@ const OrderConfirm = () => {
comments: goods.name,
deliveryType: 0,
buyerRemarks: orderRemark,
couponId: selectedCoupon ? selectedCoupon.amount : undefined
couponId: selectedCoupon ? selectedCoupon.id : undefined
}
);
@@ -268,6 +290,11 @@ const OrderConfirm = () => {
})))
setPayment(paymentRes[0])
}
// 加载优惠券(在商品信息加载完成后)
if (goodsRes) {
await loadUserCoupons()
}
} catch (err) {
console.error('加载数据失败:', err)
setError('加载数据失败,请重试')
@@ -456,35 +483,54 @@ const OrderConfirm = () => {
</View>
<View className="coupon-popup__content">
{selectedCoupon && (
<View className="coupon-popup__current">
<Text className="coupon-popup__current-title font-medium">使</Text>
<View className="coupon-popup__current-item">
<Text>{selectedCoupon.title} -{selectedCoupon.amount}</Text>
<Button size="small" onClick={handleCouponCancel}>使</Button>
</View>
{couponLoading ? (
<View className="coupon-popup__loading">
<Text>...</Text>
</View>
) : (
<>
{selectedCoupon && (
<View className="coupon-popup__current">
<Text className="coupon-popup__current-title font-medium">使</Text>
<View className="coupon-popup__current-item">
<Text>{selectedCoupon.title} -{calculateCouponDiscount(selectedCoupon, getGoodsTotal()).toFixed(2)}</Text>
<Button size="small" onClick={handleCouponCancel}>使</Button>
</View>
</View>
)}
{(() => {
const total = getGoodsTotal()
const usableCoupons = filterUsableCoupons(availableCoupons, total)
const unusableCoupons = filterUnusableCoupons(availableCoupons, total)
return (
<>
<CouponList
title={`可用优惠券 (${usableCoupons.length})`}
coupons={usableCoupons}
layout="vertical"
onCouponClick={handleCouponSelect}
showEmpty={usableCoupons.length === 0}
emptyText="暂无可用优惠券"
/>
{unusableCoupons.length > 0 && (
<CouponList
title={`不可用优惠券 (${unusableCoupons.length})`}
coupons={unusableCoupons.map(coupon => ({
...coupon,
status: 2 as const
}))}
layout="vertical"
showEmpty={false}
/>
)}
</>
)
})()}
</>
)}
<CouponList
title="可用优惠券"
coupons={availableCoupons.filter(coupon => {
const total = getGoodsTotal()
return !coupon.minAmount || total >= coupon.minAmount
})}
layout="vertical"
onCouponClick={handleCouponSelect}
/>
<CouponList
title="不可用优惠券"
coupons={availableCoupons.filter(coupon => {
const total = getGoodsTotal()
return coupon.minAmount && total < coupon.minAmount
}).map(coupon => ({...coupon, status: 2 as const}))}
layout="vertical"
showEmpty={false}
/>
</View>
</View>
</Popup>