forked from gxwebsoft/mp-10550
feat(components): 新增 GiftCard礼品卡组件
- 新增 GiftCard 组件,支持多种类型礼品卡的展示和交互 - 组件包含商品信息、价格、折扣、使用指南等丰富功能- 优化图像展示,支持单
This commit is contained in:
201
src/user/gift/demo.tsx
Normal file
201
src/user/gift/demo.tsx
Normal file
@@ -0,0 +1,201 @@
|
||||
import React, { useState } from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import { Button, Tabs, TabPane } from '@nutui/nutui-react-taro'
|
||||
import GiftCard from '@/components/GiftCard'
|
||||
import { ShopGift } from '@/api/shop/shopGift/model'
|
||||
|
||||
const GiftCardDemo: React.FC = () => {
|
||||
const [activeTab, setActiveTab] = useState('0')
|
||||
|
||||
// 模拟不同类型的礼品卡数据
|
||||
const mockGifts: ShopGift[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: '星巴克礼品卡',
|
||||
goodsName: '星巴克咖啡礼品卡(电子版)',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i1/2206571109/O1CN01QZxQJJ1Uw8QZxQJJ_!!2206571109.jpg',
|
||||
description: '享受醇香咖啡时光,适用于全国星巴克门店',
|
||||
code: 'SB2024001234567890',
|
||||
goodsId: 101,
|
||||
faceValue: '100',
|
||||
type: 20,
|
||||
useStatus: 0,
|
||||
expireTime: '2024-12-31 23:59:59',
|
||||
instructions: '请在有效期内使用,出示兑换码即可使用',
|
||||
contactInfo: '400-800-8888'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '麦当劳优惠券',
|
||||
goodsName: '麦当劳经典套餐券',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i2/2206571109/O1CN01ABC123_!!2206571109.jpg',
|
||||
description: '美味汉堡套餐,限时优惠',
|
||||
code: 'MCD2024987654321',
|
||||
goodsId: 102,
|
||||
faceValue: '50',
|
||||
type: 20,
|
||||
useStatus: 0,
|
||||
expireTime: '2024-10-31 23:59:59',
|
||||
instructions: '适用于全国麦当劳门店,不可与其他优惠同享',
|
||||
contactInfo: '400-517-517'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '海底捞火锅券',
|
||||
goodsName: '海底捞火锅代金券',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i3/2206571109/O1CN01DEF456_!!2206571109.jpg',
|
||||
description: '享受正宗川味火锅',
|
||||
code: 'HDL2024555666777',
|
||||
goodsId: 103,
|
||||
faceValue: '200',
|
||||
type: 30,
|
||||
useStatus: 1,
|
||||
useTime: '2024-08-15 19:30:00',
|
||||
useLocation: '海底捞王府井店',
|
||||
instructions: '需提前预约,适用于全国海底捞门店',
|
||||
contactInfo: '400-869-8888'
|
||||
}
|
||||
]
|
||||
|
||||
// 转换数据格式
|
||||
const transformGiftData = (gift: ShopGift) => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.goodsName || gift.name || '礼品卡',
|
||||
description: gift.description || gift.instructions,
|
||||
code: gift.code,
|
||||
goodsImage: gift.goodsImage,
|
||||
faceValue: gift.faceValue,
|
||||
type: gift.type,
|
||||
useStatus: gift.useStatus,
|
||||
expireTime: gift.expireTime,
|
||||
useTime: gift.useTime,
|
||||
useLocation: gift.useLocation,
|
||||
contactInfo: gift.contactInfo,
|
||||
goodsInfo: {
|
||||
...(gift.goodsId && {
|
||||
specification: `礼品卡面值:¥${gift.faceValue}`,
|
||||
category: getTypeText(gift.type),
|
||||
tags: [
|
||||
getTypeText(gift.type),
|
||||
gift.useStatus === 0 ? '可使用' : gift.useStatus === 1 ? '已使用' : '已过期',
|
||||
'全国通用',
|
||||
gift.type === 20 ? '即买即用' : '需预约'
|
||||
].filter(Boolean),
|
||||
instructions: gift.instructions ? [gift.instructions] : [
|
||||
'请在有效期内使用',
|
||||
'出示兑换码即可使用',
|
||||
'不可兑换现金'
|
||||
],
|
||||
notices: [
|
||||
'礼品卡一经使用不可退换',
|
||||
'请妥善保管兑换码',
|
||||
'如有疑问请联系客服'
|
||||
]
|
||||
})
|
||||
},
|
||||
showCode: gift.useStatus === 0,
|
||||
showUseBtn: gift.useStatus === 0,
|
||||
showDetailBtn: true,
|
||||
showGoodsDetail: true,
|
||||
theme: getThemeByType(gift.type),
|
||||
onUse: () => handleUse(gift),
|
||||
onDetail: () => handleDetail(gift),
|
||||
onClick: () => handleClick(gift)
|
||||
}
|
||||
}
|
||||
|
||||
const getTypeText = (type?: number): string => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
|
||||
const getThemeByType = (type?: number): 'gold' | 'silver' | 'bronze' | 'blue' | 'green' | 'purple' => {
|
||||
switch (type) {
|
||||
case 10: return 'gold'
|
||||
case 20: return 'blue'
|
||||
case 30: return 'green'
|
||||
default: return 'silver'
|
||||
}
|
||||
}
|
||||
|
||||
const handleUse = (gift: ShopGift) => {
|
||||
console.log('使用礼品卡:', gift.goodsName)
|
||||
}
|
||||
|
||||
const handleDetail = (gift: ShopGift) => {
|
||||
console.log('查看详情:', gift.goodsName)
|
||||
}
|
||||
|
||||
const handleClick = (gift: ShopGift) => {
|
||||
console.log('点击礼品卡:', gift.goodsName)
|
||||
}
|
||||
|
||||
// 根据状态筛选礼品卡
|
||||
const getFilteredGifts = () => {
|
||||
const statusMap = {
|
||||
'0': 0, // 可用
|
||||
'1': 1, // 已使用
|
||||
'2': 2 // 已过期
|
||||
}
|
||||
const targetStatus = statusMap[activeTab as keyof typeof statusMap]
|
||||
return mockGifts.filter(gift => gift.useStatus === targetStatus)
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
{/* 页面标题 */}
|
||||
<View className="bg-white px-4 py-3 border-b border-gray-100">
|
||||
<Text className="text-lg font-bold text-center">
|
||||
礼品卡商品信息展示演示
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Tab切换 */}
|
||||
<View className="bg-white">
|
||||
<Tabs value={activeTab} onChange={setActiveTab}>
|
||||
<TabPane title="可用" value="0" />
|
||||
<TabPane title="已使用" value="1" />
|
||||
<TabPane title="已过期" value="2" />
|
||||
</Tabs>
|
||||
</View>
|
||||
|
||||
{/* 礼品卡列表 */}
|
||||
<View className="p-4">
|
||||
{getFilteredGifts().map((gift) => (
|
||||
<View key={gift.id} className="mb-4">
|
||||
<GiftCard {...transformGiftData(gift)} />
|
||||
</View>
|
||||
))}
|
||||
|
||||
{getFilteredGifts().length === 0 && (
|
||||
<View className="text-center py-16">
|
||||
<Text className="text-gray-500">
|
||||
{activeTab === '0' ? '暂无可用礼品卡' :
|
||||
activeTab === '1' ? '暂无已使用礼品卡' :
|
||||
'暂无已过期礼品卡'}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 功能说明 */}
|
||||
<View className="bg-white mx-4 mb-4 p-4 rounded-lg">
|
||||
<Text className="font-bold mb-2">功能特性:</Text>
|
||||
<View className="space-y-1">
|
||||
<Text className="text-sm text-gray-600">• 优先显示商品名称(goodsName)</Text>
|
||||
<Text className="text-sm text-gray-600">• 显示商品图片(goodsImage)</Text>
|
||||
<Text className="text-sm text-gray-600">• 丰富的商品信息展示</Text>
|
||||
<Text className="text-sm text-gray-600">• 不同状态的视觉效果</Text>
|
||||
<Text className="text-sm text-gray-600">• 响应式设计适配</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default GiftCardDemo
|
||||
@@ -1,6 +1,5 @@
|
||||
export default definePageConfig({
|
||||
navigationBarTitleText: '礼品卡详情',
|
||||
navigationBarTextStyle: 'black',
|
||||
navigationBarBackgroundColor: '#ffffff',
|
||||
navigationStyle: 'custom'
|
||||
navigationBarBackgroundColor: '#ffffff'
|
||||
})
|
||||
|
||||
@@ -168,20 +168,6 @@ const GiftCardDetail = () => {
|
||||
|
||||
return (
|
||||
<ConfigProvider>
|
||||
{/* 自定义导航栏 */}
|
||||
<View className="flex items-center justify-between p-4 bg-white border-b border-gray-100">
|
||||
<View className="flex items-center" onClick={handleBack}>
|
||||
<ArrowLeft size="20" />
|
||||
<Text className="ml-2 text-lg">礼品卡详情</Text>
|
||||
</View>
|
||||
<View className="flex items-center gap-3">
|
||||
<View onClick={() => setShowShare(true)}>
|
||||
<Share size="20" className="text-gray-600" />
|
||||
</View>
|
||||
<Tag type={statusInfo.color as any}>{statusInfo.text}</Tag>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 礼品卡卡片 */}
|
||||
<View className="m-4 p-6 rounded-2xl text-white" style={{backgroundColor: '#fbbf24'}}>
|
||||
<View className="flex items-center justify-between mb-4">
|
||||
|
||||
152
src/user/gift/goodsName-integration.md
Normal file
152
src/user/gift/goodsName-integration.md
Normal file
@@ -0,0 +1,152 @@
|
||||
# GoodsName 字段集成说明
|
||||
|
||||
## 概述
|
||||
|
||||
后端已新增 `goodsName` 字段,前端已完成相应的集成工作,现在礼品卡组件可以正确显示商品名称。
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. GiftCard 组件接口更新
|
||||
|
||||
**文件**: `src/components/GiftCard.tsx`
|
||||
|
||||
```typescript
|
||||
export interface GiftCardProps {
|
||||
id: number
|
||||
name: string
|
||||
goodsName?: string // 新增:商品名称字段
|
||||
description?: string
|
||||
// ... 其他字段
|
||||
}
|
||||
```
|
||||
|
||||
**显示逻辑**:
|
||||
```typescript
|
||||
// 获取显示名称,优先使用商品名称
|
||||
const displayName = goodsName || name
|
||||
|
||||
// 在模板中使用
|
||||
<Text className="title-text">{displayName}</Text>
|
||||
```
|
||||
|
||||
### 2. 数据转换函数更新
|
||||
|
||||
**文件**: `src/user/gift/index.tsx`
|
||||
|
||||
```typescript
|
||||
const transformGiftData = (gift: ShopGift): GiftCardProps => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.name || '礼品卡',
|
||||
goodsName: gift.goodsName, // 传递商品名称
|
||||
// ... 其他字段映射
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 类型定义更新
|
||||
|
||||
**文件**: `src/types/giftCard.ts`
|
||||
|
||||
```typescript
|
||||
export interface GiftCardData {
|
||||
id: number
|
||||
name: string
|
||||
goodsName?: string // 新增字段
|
||||
// ... 其他字段
|
||||
}
|
||||
```
|
||||
|
||||
## 显示规则
|
||||
|
||||
### 优先级规则
|
||||
1. **有 `goodsName`**: 显示商品名称
|
||||
2. **无 `goodsName`**: 显示礼品卡名称 (`name`)
|
||||
|
||||
### 示例对比
|
||||
|
||||
| 数据情况 | name | goodsName | 显示结果 |
|
||||
|---------|------|-----------|----------|
|
||||
| 情况1 | "星巴克礼品卡" | "星巴克经典拿铁咖啡券" | "星巴克经典拿铁咖啡券" |
|
||||
| 情况2 | "通用礼品卡" | null/undefined | "通用礼品卡" |
|
||||
| 情况3 | "麦当劳优惠券" | "麦当劳巨无霸套餐券" | "麦当劳巨无霸套餐券" |
|
||||
|
||||
## 后端数据结构
|
||||
|
||||
确保后端返回的 `ShopGift` 对象包含 `goodsName` 字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 1,
|
||||
"name": "星巴克礼品卡",
|
||||
"goodsName": "星巴克经典拿铁咖啡券",
|
||||
"goodsImage": "https://example.com/image.jpg",
|
||||
"faceValue": "100",
|
||||
"type": 20,
|
||||
"useStatus": 0,
|
||||
// ... 其他字段
|
||||
}
|
||||
```
|
||||
|
||||
## 测试验证
|
||||
|
||||
### 测试页面
|
||||
访问测试页面验证显示效果:
|
||||
- `/user/gift/goodsname-test` - 专门测试 goodsName 字段的页面
|
||||
|
||||
### 测试用例
|
||||
1. **有商品名称的礼品卡**: 应显示 `goodsName` 的值
|
||||
2. **无商品名称的礼品卡**: 应显示 `name` 的值
|
||||
3. **不同状态的礼品卡**: 确保各种状态下名称显示正确
|
||||
4. **长名称处理**: 确保长商品名称不会破坏布局
|
||||
|
||||
## 兼容性
|
||||
|
||||
### 向后兼容
|
||||
- 对于没有 `goodsName` 字段的旧数据,组件会自动使用 `name` 字段
|
||||
- 不会影响现有功能的正常使用
|
||||
|
||||
### 数据验证
|
||||
```typescript
|
||||
// 在组件中的处理逻辑
|
||||
const displayName = goodsName || name || '礼品卡'
|
||||
```
|
||||
|
||||
## 样式优化
|
||||
|
||||
### 长名称处理
|
||||
```scss
|
||||
.title-text {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
max-width: 200px;
|
||||
}
|
||||
```
|
||||
|
||||
### 响应式适配
|
||||
- 小屏幕设备上自动调整显示宽度
|
||||
- 保持良好的视觉效果
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **数据完整性**: 建议后端确保重要礼品卡都有 `goodsName` 字段
|
||||
2. **名称长度**: 商品名称不宜过长,建议控制在20个字符以内
|
||||
3. **特殊字符**: 确保商品名称不包含可能影响显示的特殊字符
|
||||
4. **多语言**: 如需支持多语言,`goodsName` 也需要相应的国际化处理
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **搜索功能**: 在搜索时同时匹配 `name` 和 `goodsName`
|
||||
2. **排序功能**: 支持按商品名称排序
|
||||
3. **筛选功能**: 支持按是否有商品名称筛选
|
||||
4. **统计功能**: 统计有商品名称的礼品卡比例
|
||||
|
||||
## 部署检查清单
|
||||
|
||||
- [ ] 后端 API 返回 `goodsName` 字段
|
||||
- [ ] 前端组件正确显示商品名称
|
||||
- [ ] 测试页面验证通过
|
||||
- [ ] 兼容性测试通过
|
||||
- [ ] 样式在各设备上显示正常
|
||||
- [ ] 长名称处理正确
|
||||
191
src/user/gift/goodsname-test.tsx
Normal file
191
src/user/gift/goodsname-test.tsx
Normal file
@@ -0,0 +1,191 @@
|
||||
import React from 'react'
|
||||
import { View, Text } from '@tarojs/components'
|
||||
import GiftCard from '@/components/GiftCard'
|
||||
import { ShopGift } from '@/api/shop/shopGift/model'
|
||||
|
||||
const GoodsNameTest: React.FC = () => {
|
||||
// 测试数据:包含 goodsName 字段的礼品卡
|
||||
const testGifts: ShopGift[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: '星巴克礼品卡',
|
||||
goodsName: '星巴克经典拿铁咖啡券', // 后端新增的商品名称字段
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i1/2206571109/O1CN01QZxQJJ1Uw8QZxQJJ_!!2206571109.jpg',
|
||||
description: '享受醇香咖啡时光',
|
||||
code: 'SB2024001234567890',
|
||||
goodsId: 101,
|
||||
faceValue: '100',
|
||||
type: 20,
|
||||
useStatus: 0,
|
||||
expireTime: '2024-12-31 23:59:59',
|
||||
instructions: '适用于全国星巴克门店',
|
||||
contactInfo: '400-800-8888'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '麦当劳优惠券',
|
||||
goodsName: '麦当劳巨无霸套餐券', // 商品名称
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i2/2206571109/O1CN01ABC123_!!2206571109.jpg',
|
||||
description: '美味汉堡套餐',
|
||||
code: 'MCD2024987654321',
|
||||
goodsId: 102,
|
||||
faceValue: '50',
|
||||
type: 20,
|
||||
useStatus: 0,
|
||||
expireTime: '2024-10-31 23:59:59',
|
||||
instructions: '适用于全国麦当劳门店',
|
||||
contactInfo: '400-517-517'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '通用礼品卡',
|
||||
// 没有 goodsName,应该显示 name
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i3/2206571109/O1CN01DEF456_!!2206571109.jpg',
|
||||
description: '通用型礼品卡',
|
||||
code: 'GEN2024555666777',
|
||||
faceValue: '200',
|
||||
type: 10,
|
||||
useStatus: 0,
|
||||
expireTime: '2024-11-30 23:59:59',
|
||||
instructions: '可在指定商户使用',
|
||||
contactInfo: '400-123-456'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '海底捞火锅券',
|
||||
goodsName: '海底捞4人套餐券', // 已使用状态的商品
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i4/2206571109/O1CN01GHI789_!!2206571109.jpg',
|
||||
description: '享受正宗川味火锅',
|
||||
code: 'HDL2024888999000',
|
||||
goodsId: 103,
|
||||
faceValue: '300',
|
||||
type: 30,
|
||||
useStatus: 1, // 已使用
|
||||
useTime: '2024-08-15 19:30:00',
|
||||
useLocation: '海底捞王府井店',
|
||||
instructions: '需提前预约',
|
||||
contactInfo: '400-869-8888'
|
||||
}
|
||||
]
|
||||
|
||||
// 转换数据格式
|
||||
const transformGiftData = (gift: ShopGift) => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.name || '礼品卡',
|
||||
goodsName: gift.goodsName, // 传递商品名称
|
||||
description: gift.description || gift.instructions,
|
||||
code: gift.code,
|
||||
goodsImage: gift.goodsImage,
|
||||
faceValue: gift.faceValue,
|
||||
type: gift.type,
|
||||
useStatus: gift.useStatus,
|
||||
expireTime: gift.expireTime,
|
||||
useTime: gift.useTime,
|
||||
useLocation: gift.useLocation,
|
||||
contactInfo: gift.contactInfo,
|
||||
goodsInfo: {
|
||||
...((gift.goodsName || gift.goodsId) && {
|
||||
specification: `礼品卡面值:¥${gift.faceValue}`,
|
||||
category: getTypeText(gift.type),
|
||||
tags: [
|
||||
getTypeText(gift.type),
|
||||
gift.useStatus === 0 ? '可使用' : gift.useStatus === 1 ? '已使用' : '已过期',
|
||||
...(gift.goodsName ? ['商品礼品卡'] : [])
|
||||
].filter(Boolean),
|
||||
instructions: gift.instructions ? [gift.instructions] : [
|
||||
'请在有效期内使用',
|
||||
'出示兑换码即可使用',
|
||||
'不可兑换现金'
|
||||
],
|
||||
notices: [
|
||||
'礼品卡一经使用不可退换',
|
||||
'请妥善保管兑换码',
|
||||
'如有疑问请联系客服'
|
||||
]
|
||||
})
|
||||
},
|
||||
showCode: gift.useStatus === 0,
|
||||
showUseBtn: gift.useStatus === 0,
|
||||
showDetailBtn: true,
|
||||
showGoodsDetail: true,
|
||||
theme: getThemeByType(gift.type),
|
||||
onUse: () => console.log('使用:', gift.goodsName || gift.name),
|
||||
onDetail: () => console.log('详情:', gift.goodsName || gift.name),
|
||||
onClick: () => console.log('点击:', gift.goodsName || gift.name)
|
||||
}
|
||||
}
|
||||
|
||||
const getTypeText = (type?: number): string => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
|
||||
const getThemeByType = (type?: number): 'gold' | 'silver' | 'bronze' | 'blue' | 'green' | 'purple' => {
|
||||
switch (type) {
|
||||
case 10: return 'gold'
|
||||
case 20: return 'blue'
|
||||
case 30: return 'green'
|
||||
default: return 'silver'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
{/* 页面标题 */}
|
||||
<View className="bg-white px-4 py-3 border-b border-gray-100">
|
||||
<Text className="text-lg font-bold text-center">
|
||||
商品名称字段测试
|
||||
</Text>
|
||||
<Text className="text-sm text-gray-600 text-center mt-1">
|
||||
测试 goodsName 字段的显示效果
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 测试说明 */}
|
||||
<View className="bg-white mx-4 mt-4 p-4 rounded-lg">
|
||||
<Text className="font-bold mb-2">测试说明:</Text>
|
||||
<View className="space-y-1">
|
||||
<Text className="text-sm text-gray-600">• 第1张:有 goodsName,显示"星巴克经典拿铁咖啡券"</Text>
|
||||
<Text className="text-sm text-gray-600">• 第2张:有 goodsName,显示"麦当劳巨无霸套餐券"</Text>
|
||||
<Text className="text-sm text-gray-600">• 第3张:无 goodsName,显示"通用礼品卡"</Text>
|
||||
<Text className="text-sm text-gray-600">• 第4张:已使用状态,显示"海底捞4人套餐券"</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 礼品卡列表 */}
|
||||
<View className="p-4">
|
||||
{testGifts.map((gift, index) => (
|
||||
<View key={gift.id} className="mb-4">
|
||||
<View className="bg-blue-50 px-3 py-2 rounded-t-lg">
|
||||
<Text className="text-sm font-medium text-blue-800">
|
||||
测试 {index + 1}: {gift.goodsName ? `goodsName="${gift.goodsName}"` : '无 goodsName'}
|
||||
</Text>
|
||||
<Text className="text-xs text-blue-600">
|
||||
name="{gift.name}"
|
||||
</Text>
|
||||
</View>
|
||||
<GiftCard {...transformGiftData(gift)} />
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* 结果说明 */}
|
||||
<View className="bg-white mx-4 mb-4 p-4 rounded-lg">
|
||||
<Text className="font-bold mb-2">预期结果:</Text>
|
||||
<View className="space-y-1">
|
||||
<Text className="text-sm text-gray-600">✅ 有 goodsName 时,卡片标题显示商品名称</Text>
|
||||
<Text className="text-sm text-gray-600">✅ 无 goodsName 时,卡片标题显示礼品卡名称</Text>
|
||||
<Text className="text-sm text-gray-600">✅ 商品信息区域显示相关标签和说明</Text>
|
||||
<Text className="text-sm text-gray-600">✅ 不同状态的视觉效果正确</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default GoodsNameTest
|
||||
@@ -60,6 +60,7 @@ const GiftCardManage = () => {
|
||||
const res = await getUserGifts({
|
||||
page: currentPage,
|
||||
limit: 10,
|
||||
userId: Taro.getStorageSync('UserId'),
|
||||
// keywords: searchValue,
|
||||
...statusFilter,
|
||||
// 应用筛选条件
|
||||
@@ -67,7 +68,7 @@ const GiftCardManage = () => {
|
||||
// sortBy: filters.sortBy,
|
||||
// sortOrder: filters.sortOrder
|
||||
})
|
||||
|
||||
console.log(res?.list,'>>>>lalala')
|
||||
if (res && res.list) {
|
||||
const newList = isRefresh ? res.list : [...list, ...res.list]
|
||||
setList(newList)
|
||||
@@ -123,10 +124,11 @@ const GiftCardManage = () => {
|
||||
const transformGiftData = (gift: ShopGift): GiftCardProps => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.name || '礼品卡',
|
||||
description: gift.description,
|
||||
name: gift.name || '礼品卡', // 礼品卡名称
|
||||
goodsName: gift.goodsName, // 商品名称(新增字段)
|
||||
description: gift.description || gift.instructions, // 使用说明作为描述
|
||||
code: gift.code,
|
||||
goodsImage: gift.goodsImage,
|
||||
goodsImage: gift.goodsImage, // 商品图片
|
||||
faceValue: gift.faceValue,
|
||||
type: gift.type,
|
||||
useStatus: gift.useStatus,
|
||||
@@ -134,15 +136,51 @@ const GiftCardManage = () => {
|
||||
useTime: gift.useTime,
|
||||
useLocation: gift.useLocation,
|
||||
contactInfo: gift.contactInfo,
|
||||
// 添加商品信息
|
||||
goodsInfo: {
|
||||
// 如果有商品名称或商品ID,说明是关联商品的礼品卡
|
||||
...((gift.goodsName || gift.goodsId) && {
|
||||
specification: `礼品卡面值:¥${gift.faceValue}`,
|
||||
category: getTypeText(gift.type),
|
||||
tags: [
|
||||
getTypeText(gift.type),
|
||||
gift.useStatus === 0 ? '可使用' : gift.useStatus === 1 ? '已使用' : '已过期',
|
||||
...(gift.goodsName ? ['商品礼品卡'] : [])
|
||||
].filter(Boolean),
|
||||
instructions: gift.instructions ? [gift.instructions] : [
|
||||
'请在有效期内使用',
|
||||
'出示兑换码即可使用',
|
||||
'不可兑换现金',
|
||||
...(gift.goodsName ? ['此礼品卡关联具体商品'] : [])
|
||||
],
|
||||
notices: [
|
||||
'礼品卡一经使用不可退换',
|
||||
'请妥善保管兑换码',
|
||||
'如有疑问请联系客服',
|
||||
...(gift.goodsName ? ['商品以实际为准'] : [])
|
||||
]
|
||||
})
|
||||
},
|
||||
showCode: gift.useStatus === 0, // 只有可用状态显示兑换码
|
||||
showUseBtn: gift.useStatus === 0, // 只有可用状态显示使用按钮
|
||||
showDetailBtn: true,
|
||||
showGoodsDetail: true, // 显示商品详情
|
||||
theme: getThemeByType(gift.type),
|
||||
onUse: () => handleUseGift(gift),
|
||||
onDetail: () => handleGiftDetail(gift)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取礼品卡类型文本
|
||||
const getTypeText = (type?: number): string => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
|
||||
// 根据礼品卡类型获取主题色
|
||||
const getThemeByType = (type?: number): 'gold' | 'silver' | 'bronze' | 'blue' | 'green' | 'purple' => {
|
||||
switch (type) {
|
||||
@@ -188,31 +226,31 @@ const GiftCardManage = () => {
|
||||
}
|
||||
|
||||
// 加载礼品卡统计数据
|
||||
const loadGiftStats = async () => {
|
||||
try {
|
||||
// 并行获取各状态的礼品卡数量
|
||||
const [availableRes, usedRes, expiredRes] = await Promise.all([
|
||||
getUserGifts({ page: 1, limit: 1, useStatus: 0 }),
|
||||
getUserGifts({ page: 1, limit: 1, useStatus: 1 }),
|
||||
getUserGifts({ page: 1, limit: 1, useStatus: 2 })
|
||||
])
|
||||
|
||||
// 计算总价值(仅可用礼品卡)
|
||||
const availableGifts = await getUserGifts({ page: 1, limit: 100, useStatus: 0 })
|
||||
const totalValue = availableGifts?.list?.reduce((sum, gift) => {
|
||||
return sum + parseFloat(gift.faceValue || '0')
|
||||
}, 0) || 0
|
||||
|
||||
setStats({
|
||||
available: availableRes?.count || 0,
|
||||
used: usedRes?.count || 0,
|
||||
expired: expiredRes?.count || 0,
|
||||
totalValue
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('获取礼品卡统计失败:', error)
|
||||
}
|
||||
}
|
||||
// const loadGiftStats = async () => {
|
||||
// try {
|
||||
// // 并行获取各状态的礼品卡数量
|
||||
// const [availableRes, usedRes, expiredRes] = await Promise.all([
|
||||
// getUserGifts({ page: 1, limit: 1, useStatus: 0 }),
|
||||
// getUserGifts({ page: 1, limit: 1, useStatus: 1 }),
|
||||
// getUserGifts({ page: 1, limit: 1, useStatus: 2 })
|
||||
// ])
|
||||
//
|
||||
// // 计算总价值(仅可用礼品卡)
|
||||
// const availableGifts = await getUserGifts({ page: 1, limit: 100, useStatus: 0 })
|
||||
// const totalValue = availableGifts?.list?.reduce((sum, gift) => {
|
||||
// return sum + parseFloat(gift.faceValue || '0')
|
||||
// }, 0) || 0
|
||||
//
|
||||
// setStats({
|
||||
// available: availableRes?.count || 0,
|
||||
// used: usedRes?.count || 0,
|
||||
// expired: expiredRes?.count || 0,
|
||||
// totalValue
|
||||
// })
|
||||
// } catch (error) {
|
||||
// console.error('获取礼品卡统计失败:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
// 统计卡片点击事件
|
||||
const handleStatsClick = (type: 'available' | 'used' | 'expired' | 'total') => {
|
||||
@@ -264,7 +302,7 @@ const GiftCardManage = () => {
|
||||
|
||||
useDidShow(() => {
|
||||
reload(true).then()
|
||||
loadGiftStats().then()
|
||||
// loadGiftStats().then()
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
130
src/user/gift/test.tsx
Normal file
130
src/user/gift/test.tsx
Normal file
@@ -0,0 +1,130 @@
|
||||
import React from 'react'
|
||||
import { View } from '@tarojs/components'
|
||||
import GiftCard from '@/components/GiftCard'
|
||||
import { ShopGift } from '@/api/shop/shopGift/model'
|
||||
|
||||
const GiftCardTest: React.FC = () => {
|
||||
// 模拟礼品卡数据,包含商品名称和图片
|
||||
const mockGiftData: ShopGift = {
|
||||
id: 1,
|
||||
name: '星巴克礼品卡',
|
||||
goodsName: '星巴克咖啡礼品卡(电子版)', // 商品名称
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i1/2206571109/O1CN01QZxQJJ1Uw8QZxQJJ_!!2206571109.jpg', // 商品图片
|
||||
description: '享受醇香咖啡时光,适用于全国星巴克门店',
|
||||
code: 'SB2024001234567890',
|
||||
goodsId: 101,
|
||||
faceValue: '100',
|
||||
type: 20, // 虚拟礼品卡
|
||||
useStatus: 0, // 可用
|
||||
expireTime: '2024-12-31 23:59:59',
|
||||
instructions: '请在有效期内使用,出示兑换码即可使用',
|
||||
contactInfo: '400-800-8888',
|
||||
createTime: '2024-08-01 10:00:00'
|
||||
}
|
||||
|
||||
// 转换数据格式
|
||||
const transformGiftData = (gift: ShopGift) => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.goodsName || gift.name || '礼品卡', // 优先显示商品名称
|
||||
description: gift.description || gift.instructions,
|
||||
code: gift.code,
|
||||
goodsImage: gift.goodsImage, // 商品图片
|
||||
faceValue: gift.faceValue,
|
||||
type: gift.type,
|
||||
useStatus: gift.useStatus,
|
||||
expireTime: gift.expireTime,
|
||||
contactInfo: gift.contactInfo,
|
||||
// 添加商品信息
|
||||
goodsInfo: {
|
||||
...(gift.goodsId && {
|
||||
specification: `礼品卡面值:¥${gift.faceValue}`,
|
||||
category: getTypeText(gift.type),
|
||||
tags: [
|
||||
getTypeText(gift.type),
|
||||
gift.useStatus === 0 ? '可使用' : gift.useStatus === 1 ? '已使用' : '已过期',
|
||||
'全国通用',
|
||||
'即买即用'
|
||||
].filter(Boolean),
|
||||
instructions: gift.instructions ? [gift.instructions] : [
|
||||
'请在有效期内使用',
|
||||
'出示兑换码即可使用',
|
||||
'不可兑换现金',
|
||||
'可用于购买任意饮品和食品'
|
||||
],
|
||||
notices: [
|
||||
'礼品卡一经使用不可退换',
|
||||
'请妥善保管兑换码',
|
||||
'如有疑问请联系客服',
|
||||
'部分特殊商品可能不适用'
|
||||
]
|
||||
})
|
||||
},
|
||||
showCode: gift.useStatus === 0,
|
||||
showUseBtn: gift.useStatus === 0,
|
||||
showDetailBtn: true,
|
||||
showGoodsDetail: true,
|
||||
theme: 'green' as const,
|
||||
onUse: () => console.log('使用礼品卡'),
|
||||
onDetail: () => console.log('查看详情')
|
||||
}
|
||||
}
|
||||
|
||||
const getTypeText = (type?: number): string => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
|
||||
// 多个测试数据
|
||||
const testGifts: ShopGift[] = [
|
||||
{
|
||||
...mockGiftData,
|
||||
id: 1,
|
||||
goodsName: '星巴克咖啡礼品卡(电子版)',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i1/2206571109/O1CN01QZxQJJ1Uw8QZxQJJ_!!2206571109.jpg'
|
||||
},
|
||||
{
|
||||
...mockGiftData,
|
||||
id: 2,
|
||||
goodsName: '麦当劳优惠券套餐',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i2/2206571109/O1CN01ABC123_!!2206571109.jpg',
|
||||
faceValue: '50',
|
||||
type: 20,
|
||||
useStatus: 0
|
||||
},
|
||||
{
|
||||
...mockGiftData,
|
||||
id: 3,
|
||||
goodsName: '海底捞火锅券',
|
||||
goodsImage: 'https://img.alicdn.com/imgextra/i3/2206571109/O1CN01DEF456_!!2206571109.jpg',
|
||||
faceValue: '200',
|
||||
type: 30,
|
||||
useStatus: 1,
|
||||
useTime: '2024-08-15 19:30:00'
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<View className="bg-gray-50 min-h-screen">
|
||||
<View className="p-4">
|
||||
<View className="text-lg font-bold mb-4 text-center">
|
||||
礼品卡商品信息展示测试
|
||||
</View>
|
||||
|
||||
{testGifts.map((gift, index) => (
|
||||
<View key={gift.id} className="mb-4">
|
||||
<GiftCard
|
||||
{...transformGiftData(gift)}
|
||||
/>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
export default GiftCardTest
|
||||
145
src/user/gift/usage-example.md
Normal file
145
src/user/gift/usage-example.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 礼品卡商品信息显示使用说明
|
||||
|
||||
## 概述
|
||||
|
||||
已成功优化礼品卡组件,现在可以正确显示商品名称和图片。主要改进包括:
|
||||
|
||||
1. **优先显示商品名称**:`goodsName` 优先于 `name` 显示
|
||||
2. **显示商品图片**:使用 `goodsImage` 字段显示商品图片
|
||||
3. **丰富的商品信息**:包括规格、分类、标签、使用说明等
|
||||
4. **更好的用户体验**:清晰的信息层次和视觉效果
|
||||
|
||||
## 数据结构
|
||||
|
||||
### ShopGift 模型中的关键字段
|
||||
|
||||
```typescript
|
||||
interface ShopGift {
|
||||
id?: number;
|
||||
name?: string; // 礼品卡名称
|
||||
goodsName?: string; // 商品名称(优先显示)
|
||||
goodsImage?: string; // 商品图片
|
||||
goodsId?: number; // 关联商品ID
|
||||
description?: string; // 礼品卡描述
|
||||
faceValue?: string; // 面值
|
||||
type?: number; // 类型(10实物 20虚拟 30服务)
|
||||
useStatus?: number; // 状态(0可用 1已使用 2已过期)
|
||||
// ... 其他字段
|
||||
}
|
||||
```
|
||||
|
||||
## 代码实现
|
||||
|
||||
### 1. 数据转换函数
|
||||
|
||||
在 `src/user/gift/index.tsx` 中的 `transformGiftData` 函数已经优化:
|
||||
|
||||
```typescript
|
||||
const transformGiftData = (gift: ShopGift): GiftCardProps => {
|
||||
return {
|
||||
id: gift.id || 0,
|
||||
name: gift.goodsName || gift.name || '礼品卡', // 优先显示商品名称
|
||||
description: gift.description || gift.instructions,
|
||||
code: gift.code,
|
||||
goodsImage: gift.goodsImage, // 商品图片
|
||||
faceValue: gift.faceValue,
|
||||
type: gift.type,
|
||||
useStatus: gift.useStatus,
|
||||
expireTime: gift.expireTime,
|
||||
useTime: gift.useTime,
|
||||
useLocation: gift.useLocation,
|
||||
contactInfo: gift.contactInfo,
|
||||
// 添加商品信息
|
||||
goodsInfo: {
|
||||
...(gift.goodsId && {
|
||||
specification: `礼品卡面值:¥${gift.faceValue}`,
|
||||
category: getTypeText(gift.type),
|
||||
tags: [
|
||||
getTypeText(gift.type),
|
||||
gift.useStatus === 0 ? '可使用' : gift.useStatus === 1 ? '已使用' : '已过期'
|
||||
].filter(Boolean),
|
||||
instructions: gift.instructions ? [gift.instructions] : [
|
||||
'请在有效期内使用',
|
||||
'出示兑换码即可使用',
|
||||
'不可兑换现金'
|
||||
],
|
||||
notices: [
|
||||
'礼品卡一经使用不可退换',
|
||||
'请妥善保管兑换码',
|
||||
'如有疑问请联系客服'
|
||||
]
|
||||
})
|
||||
},
|
||||
showCode: gift.useStatus === 0,
|
||||
showUseBtn: gift.useStatus === 0,
|
||||
showDetailBtn: true,
|
||||
showGoodsDetail: true, // 显示商品详情
|
||||
theme: getThemeByType(gift.type),
|
||||
onUse: () => handleUseGift(gift),
|
||||
onDetail: () => handleGiftDetail(gift)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 类型文本获取函数
|
||||
|
||||
```typescript
|
||||
const getTypeText = (type?: number): string => {
|
||||
switch (type) {
|
||||
case 10: return '实物礼品卡'
|
||||
case 20: return '虚拟礼品卡'
|
||||
case 30: return '服务礼品卡'
|
||||
default: return '礼品卡'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 显示效果
|
||||
|
||||
### 商品信息展示包括:
|
||||
|
||||
1. **基础信息**
|
||||
- 商品名称(优先显示)
|
||||
- 商品图片
|
||||
- 礼品卡面值
|
||||
- 商品分类
|
||||
|
||||
2. **详细信息**
|
||||
- 商品规格
|
||||
- 商品标签
|
||||
- 使用说明
|
||||
- 注意事项
|
||||
|
||||
3. **状态信息**
|
||||
- 使用状态标识
|
||||
- 过期时间提醒
|
||||
- 兑换码显示
|
||||
|
||||
## 测试验证
|
||||
|
||||
可以使用测试页面验证显示效果:
|
||||
|
||||
```bash
|
||||
# 访问测试页面
|
||||
/user/gift/test
|
||||
```
|
||||
|
||||
测试页面包含了不同类型和状态的礼品卡示例,可以验证:
|
||||
- 商品名称正确显示
|
||||
- 商品图片正常加载
|
||||
- 商品信息完整展示
|
||||
- 不同状态的样式效果
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **图片加载**:确保 `goodsImage` 字段包含有效的图片URL
|
||||
2. **数据完整性**:建议在后端确保 `goodsName` 和 `goodsImage` 字段有值
|
||||
3. **兼容性**:保持对旧数据的兼容,当 `goodsName` 为空时使用 `name` 字段
|
||||
4. **性能优化**:大量礼品卡列表时注意图片懒加载
|
||||
|
||||
## 后续优化建议
|
||||
|
||||
1. **图片优化**:添加图片懒加载和占位符
|
||||
2. **缓存机制**:对商品信息进行本地缓存
|
||||
3. **错误处理**:添加图片加载失败的降级处理
|
||||
4. **用户体验**:添加骨架屏和加载状态
|
||||
Reference in New Issue
Block a user