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

@@ -117,12 +117,16 @@
.coupon-right {
flex: 1;
display: flex;
flex-direction: column;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding: 16px;
.coupon-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
.coupon-title {
font-size: 32px;
@@ -143,6 +147,7 @@
display: flex;
justify-content: flex-end;
align-items: center;
flex-shrink: 0;
.coupon-btn {
min-width: 120px;

View File

@@ -4,20 +4,32 @@ import { Button } from '@nutui/nutui-react-taro'
import './CouponCard.scss'
export interface CouponCardProps {
/** 优惠券ID */
id?: string
/** 优惠券金额 */
amount: number
/** 最低消费金额 */
minAmount?: number
/** 优惠券类型1-满减券 2-折扣券 3-免费券 */
type?: 1 | 2 | 3
/** 优惠券类型10-满减券 20-折扣券 30-免费券 */
type?: 10 | 20 | 30
/** 优惠券状态0-未使用 1-已使用 2-已过期 */
status?: 0 | 1 | 2
/** 状态文本描述(后端返回) */
statusText?: string
/** 优惠券标题 */
title?: string
/** 优惠券描述 */
description?: string
/** 有效期开始时间 */
startTime?: string
/** 有效期结束时间 */
endTime?: string
/** 是否即将过期(后端计算) */
isExpiringSoon?: boolean
/** 剩余天数(后端计算) */
daysRemaining?: number
/** 剩余小时数(后端计算) */
hoursRemaining?: number
/** 是否显示领取按钮 */
showReceiveBtn?: boolean
/** 是否显示使用按钮 */
@@ -33,11 +45,15 @@ export interface CouponCardProps {
const CouponCard: React.FC<CouponCardProps> = ({
amount,
minAmount,
type = 1,
type = 10,
status = 0,
statusText,
title,
startTime,
endTime,
isExpiringSoon,
daysRemaining,
hoursRemaining,
showReceiveBtn = false,
showUseBtn = false,
onReceive,
@@ -49,14 +65,13 @@ const CouponCard: React.FC<CouponCardProps> = ({
return `theme-${theme}`
}
// 格式化优惠券金额显示
// @ts-ignore
const formatAmount = () => {
switch (type) {
case 1: // 满减券
case 10: // 满减券
return `¥${amount}`
case 2: // 折扣券
case 20: // 折扣券
return `${amount}`
case 3: // 免费券
case 30: // 免费券
return '免费'
default:
return `¥${amount}`
@@ -65,21 +80,27 @@ const CouponCard: React.FC<CouponCardProps> = ({
// 获取优惠券状态文本
const getStatusText = () => {
// 优先使用后端返回的状态文本
if (statusText) {
return statusText
}
// 兜底逻辑
switch (status) {
case 0:
return '未使用'
return '用'
case 1:
return '已使用'
case 2:
return '已过期'
default:
return '未使用'
return '用'
}
}
// 获取使用条件文本
const getConditionText = () => {
if (type === 3) return '免费使用' // 免费券
if (type === 30) return '免费使用' // 免费券
if (minAmount && minAmount > 0) {
return `${minAmount}元可用`
}
@@ -88,15 +109,40 @@ const CouponCard: React.FC<CouponCardProps> = ({
// 格式化有效期显示
const formatValidityPeriod = () => {
if (!startTime || !endTime) return ''
// 第一优先级:使用后端返回的状态文本
if (statusText) {
return statusText
}
// 第二优先级:根据状态码显示
if (status === 2) {
return '已过期'
}
if (status === 1) {
return '已使用'
}
// 第三优先级:使用后端计算的剩余时间
if (isExpiringSoon && daysRemaining !== undefined) {
if (daysRemaining <= 0 && hoursRemaining !== undefined) {
return `${hoursRemaining}小时后过期`
}
return `${daysRemaining}天后过期`
}
// 兜底逻辑:使用前端计算
if (!endTime) return '可用'
const start = new Date(startTime)
const end = new Date(endTime)
const now = new Date()
// 如果还未开始
if (now < start) {
return `${start.getMonth() + 1}.${start.getDate()} 开始生效`
if (startTime) {
const start = new Date(startTime)
// 如果还未开始
if (now < start) {
return `${start.getMonth() + 1}.${start.getDate()} 开始生效`
}
}
// 计算剩余天数
@@ -112,25 +158,6 @@ const CouponCard: React.FC<CouponCardProps> = ({
}
}
// 格式化日期
const formatDate = (dateStr?: string) => {
if (!dateStr) return ''
const date = new Date(dateStr)
return `${date.getMonth() + 1}.${date.getDate()}`
}
// 获取有效期文本
const getValidityText = () => {
if (startTime && endTime) {
return `${formatDate(startTime)}-${formatDate(endTime)}`
}
return ''
}
console.log(getValidityText)
const themeClass = getThemeClass()
return (
@@ -138,7 +165,7 @@ const CouponCard: React.FC<CouponCardProps> = ({
{/* 左侧金额区域 */}
<View className={`coupon-left ${themeClass}`}>
<View className="amount-wrapper">
{type !== 3 && <Text className="currency">¥</Text>}
{type !== 30 && <Text className="currency">¥</Text>}
<Text className="amount">{formatAmount()}</Text>
</View>
<View className="condition">
@@ -157,7 +184,7 @@ const CouponCard: React.FC<CouponCardProps> = ({
<View className="coupon-right">
<View className="coupon-info">
<View className="coupon-title">
{title || (type === 1 ? '满减券' : type === 2 ? '折扣券' : '免费券')}
{title || (type === 10 ? '满减券' : type === 20 ? '折扣券' : '免费券')}
</View>
<View className="coupon-validity">
{formatValidityPeriod()}

View File

@@ -73,12 +73,12 @@ const SpecSelector: React.FC<SpecSelectorProps> = ({
}, [selectedSpecs, skus, specGroups]);
// 选择规格值
const handleSpecSelect = (specName: string, specValue: string) => {
setSelectedSpecs(prev => ({
...prev,
[specName]: specValue
}));
};
// const handleSpecSelect = (specName: string, specValue: string) => {
// setSelectedSpecs(prev => ({
// ...prev,
// [specName]: specValue
// }));
// };
// 确认选择
const handleConfirm = () => {
@@ -89,21 +89,21 @@ const SpecSelector: React.FC<SpecSelectorProps> = ({
};
// 检查规格值是否可选是否有对应的SKU且有库存
const isSpecValueAvailable = (specName: string, specValue: string) => {
const testSpecs = { ...selectedSpecs, [specName]: specValue };
// 如果还有其他规格未选择,则认为可选
if (Object.keys(testSpecs).length < specGroups.length) {
return true;
}
// 构建规格值字符串
const sortedSpecNames = specGroups.map(g => g.specName).sort();
const specValues = sortedSpecNames.map(name => testSpecs[name]).join('|');
const sku = skus.find(s => s.sku === specValues);
return sku && sku.stock && sku.stock > 0 && sku.status === 0;
};
// const isSpecValueAvailable = (specName: string, specValue: string) => {
// const testSpecs = { ...selectedSpecs, [specName]: specValue };
//
// // 如果还有其他规格未选择,则认为可选
// if (Object.keys(testSpecs).length < specGroups.length) {
// return true;
// }
//
// // 构建规格值字符串
// const sortedSpecNames = specGroups.map(g => g.specName).sort();
// const specValues = sortedSpecNames.map(name => testSpecs[name]).join('|');
//
// const sku = skus.find(s => s.sku === specValues);
// return sku && sku.stock && sku.stock > 0 && sku.status === 0;
// };
return (
<Popup