5 changed files with 700 additions and 0 deletions
@ -0,0 +1,181 @@ |
|||
# 后端多规格功能适配指南 |
|||
|
|||
## 概述 |
|||
前端已完成商品多规格功能集成,需要后端相应适配以支持完整的多规格商品流程。 |
|||
|
|||
## 需要适配的API接口 |
|||
|
|||
### 1. 商品规格查询接口 |
|||
**接口**: `GET /shop/shop-goods-spec` |
|||
**当前问题**: 参数模型中缺少 `goodsId` 字段 |
|||
**需要修改**: |
|||
```java |
|||
// ShopGoodsSpecParam 类需要添加 goodsId 字段 |
|||
public class ShopGoodsSpecParam extends PageParam { |
|||
private Long goodsId; // 添加此字段 |
|||
private Long id; |
|||
private String keywords; |
|||
// ... getter/setter |
|||
} |
|||
``` |
|||
|
|||
### 2. 商品SKU查询接口 |
|||
**接口**: `GET /shop/shop-goods-sku` |
|||
**当前问题**: 参数模型中缺少 `goodsId` 字段 |
|||
**需要修改**: |
|||
```java |
|||
// ShopGoodsSkuParam 类需要添加 goodsId 字段 |
|||
public class ShopGoodsSkuParam extends PageParam { |
|||
private Long goodsId; // 添加此字段 |
|||
private Long id; |
|||
private String keywords; |
|||
// ... getter/setter |
|||
} |
|||
``` |
|||
|
|||
### 3. 购物车接口适配 |
|||
**当前购物车数据结构**: |
|||
```typescript |
|||
interface CartItem { |
|||
goodsId: number; |
|||
name: string; |
|||
price: string; |
|||
image: string; |
|||
quantity: number; |
|||
addTime: number; |
|||
skuId?: number; // 新增SKU ID |
|||
specInfo?: string; // 新增规格信息 |
|||
} |
|||
``` |
|||
|
|||
**后端需要适配**: |
|||
- 购物车存储时支持 `skuId` 和 `specInfo` 字段 |
|||
- 购物车查询时返回完整的SKU信息 |
|||
- 价格计算时优先使用SKU价格 |
|||
|
|||
### 4. 订单创建接口适配 |
|||
**前端订单数据结构**: |
|||
```typescript |
|||
interface OrderGoodsItem { |
|||
goodsId: number; |
|||
quantity: number; |
|||
skuId?: number; // SKU ID |
|||
specInfo?: string; // 规格信息字符串 |
|||
} |
|||
``` |
|||
|
|||
**后端需要处理**: |
|||
- 订单商品项支持SKU信息 |
|||
- 库存扣减时根据SKU进行 |
|||
- 价格计算时使用SKU价格 |
|||
- 订单详情显示规格信息 |
|||
|
|||
## 数据库表结构检查 |
|||
|
|||
### 1. 购物车表 (如果有) |
|||
确保包含以下字段: |
|||
```sql |
|||
ALTER TABLE shop_cart ADD COLUMN sku_id BIGINT COMMENT 'SKU ID'; |
|||
ALTER TABLE shop_cart ADD COLUMN spec_info VARCHAR(500) COMMENT '规格信息'; |
|||
``` |
|||
|
|||
### 2. 订单商品表 |
|||
确保包含以下字段: |
|||
```sql |
|||
-- shop_order_goods 表应该已有这些字段 |
|||
-- sku_id BIGINT COMMENT 'SKU ID' |
|||
-- spec VARCHAR(255) COMMENT '商品规格' |
|||
``` |
|||
|
|||
## 业务逻辑适配 |
|||
|
|||
### 1. 库存管理 |
|||
- 单规格商品:使用 `shop_goods.stock` |
|||
- 多规格商品:使用 `shop_goods_sku.stock` |
|||
- 下单时根据是否有SKU选择对应的库存扣减逻辑 |
|||
|
|||
### 2. 价格计算 |
|||
- 单规格商品:使用 `shop_goods.price` |
|||
- 多规格商品:使用 `shop_goods_sku.price` |
|||
- 订单金额计算时优先使用SKU价格 |
|||
|
|||
### 3. 规格数据组织 |
|||
后端查询规格时需要按商品ID过滤: |
|||
```java |
|||
// 示例查询逻辑 |
|||
public List<ShopGoodsSpec> listByGoodsId(Long goodsId) { |
|||
return shopGoodsSpecMapper.selectList( |
|||
new QueryWrapper<ShopGoodsSpec>() |
|||
.eq("goods_id", goodsId) |
|||
.orderByAsc("spec_name", "spec_value") |
|||
); |
|||
} |
|||
``` |
|||
|
|||
## 前端调用示例 |
|||
|
|||
### 1. 加载商品规格 |
|||
```typescript |
|||
// 前端会这样调用 |
|||
listShopGoodsSpec({ goodsId: 123 }) |
|||
listShopGoodsSku({ goodsId: 123 }) |
|||
``` |
|||
|
|||
### 2. 创建订单 |
|||
```typescript |
|||
// 单规格商品 |
|||
{ |
|||
goodsItems: [{ |
|||
goodsId: 123, |
|||
quantity: 2 |
|||
}] |
|||
} |
|||
|
|||
// 多规格商品 |
|||
{ |
|||
goodsItems: [{ |
|||
goodsId: 123, |
|||
quantity: 2, |
|||
skuId: 456, |
|||
specInfo: "颜色:红色|尺寸:L" |
|||
}] |
|||
} |
|||
``` |
|||
|
|||
## 测试建议 |
|||
|
|||
1. **创建测试数据**: |
|||
- 创建一个多规格商品 |
|||
- 添加规格组(颜色、尺寸等) |
|||
- 生成对应的SKU数据 |
|||
|
|||
2. **测试场景**: |
|||
- 商品详情页规格加载 |
|||
- 规格选择和SKU匹配 |
|||
- 加入购物车(多规格) |
|||
- 立即购买(多规格) |
|||
- 订单创建和支付 |
|||
|
|||
3. **边界情况**: |
|||
- SKU库存为0的处理 |
|||
- 规格数据不完整的处理 |
|||
- 单规格和多规格商品混合购买 |
|||
|
|||
## 注意事项 |
|||
|
|||
1. **向后兼容**: 确保单规格商品的现有功能不受影响 |
|||
2. **数据一致性**: SKU价格和库存与主商品数据的同步 |
|||
3. **性能优化**: 规格和SKU数据的查询优化 |
|||
4. **错误处理**: 规格选择错误、库存不足等异常情况的处理 |
|||
|
|||
## 完成检查清单 |
|||
|
|||
- [ ] ShopGoodsSpecParam 添加 goodsId 字段 |
|||
- [ ] ShopGoodsSkuParam 添加 goodsId 字段 |
|||
- [ ] 规格查询接口支持按商品ID过滤 |
|||
- [ ] SKU查询接口支持按商品ID过滤 |
|||
- [ ] 购物车接口支持SKU信息 |
|||
- [ ] 订单创建接口支持SKU信息 |
|||
- [ ] 库存扣减逻辑适配多规格 |
|||
- [ ] 价格计算逻辑适配多规格 |
|||
- [ ] 测试多规格商品完整流程 |
@ -0,0 +1,154 @@ |
|||
# 前端多规格功能测试指南 |
|||
|
|||
## 功能概述 |
|||
已完成商品详情页多规格功能集成,包括: |
|||
- 规格数据加载 |
|||
- 规格选择器组件 |
|||
- 购物车支持SKU信息 |
|||
- 立即购买支持SKU信息 |
|||
|
|||
## 测试步骤 |
|||
|
|||
### 1. 准备测试数据 |
|||
在后端创建一个多规格商品,包含: |
|||
- 基础商品信息 |
|||
- 规格组:颜色(红色、蓝色)、尺寸(S、M、L) |
|||
- 对应的SKU数据 |
|||
|
|||
### 2. 商品详情页测试 |
|||
1. 访问商品详情页:`/shop/goodsDetail/index?id={商品ID}` |
|||
2. 检查是否正确加载: |
|||
- 商品基本信息 |
|||
- 商品图片轮播 |
|||
- 价格显示 |
|||
|
|||
### 3. 规格选择测试 |
|||
1. 点击"加入购物车"按钮 |
|||
2. 应该弹出规格选择器 |
|||
3. 检查规格选择器内容: |
|||
- 商品图片和基本信息 |
|||
- 规格组显示(颜色、尺寸) |
|||
- 规格值选项 |
|||
- 数量选择器 |
|||
|
|||
### 4. 规格交互测试 |
|||
1. 选择不同规格组合 |
|||
2. 检查: |
|||
- SKU价格更新 |
|||
- 库存数量更新 |
|||
- 不可选规格置灰 |
|||
- 数量限制(不超过库存) |
|||
|
|||
### 5. 加入购物车测试 |
|||
1. 选择完整规格 |
|||
2. 设置购买数量 |
|||
3. 点击确定 |
|||
4. 检查: |
|||
- 成功提示 |
|||
- 购物车数量更新 |
|||
- 购物车页面显示规格信息 |
|||
|
|||
### 6. 立即购买测试 |
|||
1. 点击"立即购买"按钮 |
|||
2. 选择规格和数量 |
|||
3. 点击确定 |
|||
4. 检查是否正确跳转到订单确认页 |
|||
|
|||
## 预期行为 |
|||
|
|||
### 单规格商品 |
|||
- 直接加入购物车/立即购买 |
|||
- 不显示规格选择器 |
|||
|
|||
### 多规格商品 |
|||
- 必须选择规格才能操作 |
|||
- 显示规格选择器 |
|||
- 根据选择更新价格和库存 |
|||
|
|||
## 数据流验证 |
|||
|
|||
### 1. API调用检查 |
|||
打开浏览器开发者工具,检查以下API调用: |
|||
``` |
|||
GET /shop/shop-goods/{id} // 商品详情 |
|||
GET /shop/shop-goods-spec?goodsId={id} // 商品规格 |
|||
GET /shop/shop-goods-sku?goodsId={id} // 商品SKU |
|||
``` |
|||
|
|||
### 2. 购物车数据检查 |
|||
检查本地存储中的购物车数据: |
|||
```javascript |
|||
// 在浏览器控制台执行 |
|||
JSON.parse(localStorage.getItem('cart_items') || '[]') |
|||
``` |
|||
|
|||
应该包含SKU信息: |
|||
```json |
|||
[{ |
|||
"goodsId": 123, |
|||
"name": "测试商品", |
|||
"price": "99.00", |
|||
"image": "...", |
|||
"quantity": 2, |
|||
"skuId": 456, |
|||
"specInfo": "颜色:红色|尺寸:L", |
|||
"addTime": 1640995200000 |
|||
}] |
|||
``` |
|||
|
|||
## 常见问题排查 |
|||
|
|||
### 1. 规格选择器不显示 |
|||
- 检查 `specs` 数组是否有数据 |
|||
- 检查 `showSpecSelector` 状态 |
|||
- 检查API返回数据格式 |
|||
|
|||
### 2. SKU匹配失败 |
|||
- 检查规格值字符串格式 |
|||
- 检查SKU数据中的 `sku` 字段格式 |
|||
- 确认规格名称排序一致性 |
|||
|
|||
### 3. 价格不更新 |
|||
- 检查SKU数据中的 `price` 字段 |
|||
- 检查 `selectedSku` 状态更新 |
|||
- 确认价格显示逻辑 |
|||
|
|||
### 4. 库存显示错误 |
|||
- 检查SKU数据中的 `stock` 字段 |
|||
- 检查库存为0时的处理逻辑 |
|||
- 确认数量选择器的最大值限制 |
|||
|
|||
## 调试技巧 |
|||
|
|||
### 1. 控制台日志 |
|||
在关键位置添加日志: |
|||
```javascript |
|||
console.log('Specs loaded:', specs); |
|||
console.log('SKUs loaded:', skus); |
|||
console.log('Selected SKU:', selectedSku); |
|||
``` |
|||
|
|||
### 2. React DevTools |
|||
使用React DevTools检查组件状态: |
|||
- GoodsDetail组件的state |
|||
- SpecSelector组件的props和state |
|||
|
|||
### 3. 网络面板 |
|||
检查API请求和响应: |
|||
- 请求参数是否正确 |
|||
- 响应数据格式是否符合预期 |
|||
- 是否有错误状态码 |
|||
|
|||
## 性能优化建议 |
|||
|
|||
1. **数据预加载**: 考虑在商品详情加载时同时加载规格数据 |
|||
2. **缓存策略**: 对规格数据进行适当缓存 |
|||
3. **懒加载**: 规格选择器可以考虑懒加载 |
|||
4. **防抖处理**: 规格选择时的价格更新可以添加防抖 |
|||
|
|||
## 后续优化方向 |
|||
|
|||
1. **规格图片**: 支持规格值对应的商品图片 |
|||
2. **规格预设**: 支持默认选中某个规格组合 |
|||
3. **批量操作**: 支持批量添加不同规格的商品 |
|||
4. **规格搜索**: 在规格较多时支持搜索功能 |
@ -0,0 +1,189 @@ |
|||
# 商品多规格功能集成总结 |
|||
|
|||
## 完成的工作 |
|||
|
|||
### 1. 前端功能集成 ✅ |
|||
|
|||
#### 商品详情页改造 |
|||
- **文件**: `src/shop/goodsDetail/index.tsx` |
|||
- **新增功能**: |
|||
- 加载商品规格数据 (`listShopGoodsSpec`) |
|||
- 加载商品SKU数据 (`listShopGoodsSku`) |
|||
- 集成规格选择器组件 |
|||
- 支持多规格加入购物车 |
|||
- 支持多规格立即购买 |
|||
|
|||
#### 购物车系统升级 |
|||
- **文件**: `src/hooks/useCart.ts` |
|||
- **改进内容**: |
|||
- `CartItem` 接口新增 `skuId` 和 `specInfo` 字段 |
|||
- `addToCart` 函数支持SKU信息 |
|||
- 购物车商品唯一性判断支持SKU区分 |
|||
|
|||
#### 规格选择器组件优化 |
|||
- **文件**: `src/components/SpecSelector/index.tsx` |
|||
- **改进内容**: |
|||
- 支持 `action` 参数区分加入购物车和立即购买 |
|||
- 优化回调函数参数传递 |
|||
- 改进组件接口设计 |
|||
|
|||
### 2. 数据流设计 ✅ |
|||
|
|||
#### API调用流程 |
|||
``` |
|||
商品详情页加载 |
|||
├── getShopGoods(goodsId) - 获取商品基本信息 |
|||
├── listShopGoodsSpec(goodsId) - 获取商品规格 |
|||
└── listShopGoodsSku(goodsId) - 获取商品SKU |
|||
``` |
|||
|
|||
#### 用户操作流程 |
|||
``` |
|||
用户点击加入购物车/立即购买 |
|||
├── 检查是否有规格 (specs.length > 0) |
|||
├── 有规格: 显示规格选择器 |
|||
│ ├── 用户选择规格组合 |
|||
│ ├── 系统匹配对应SKU |
|||
│ ├── 更新价格和库存显示 |
|||
│ └── 确认后执行对应操作 |
|||
└── 无规格: 直接执行操作 |
|||
``` |
|||
|
|||
#### 数据结构设计 |
|||
```typescript |
|||
// 购物车商品项 |
|||
interface CartItem { |
|||
goodsId: number; |
|||
name: string; |
|||
price: string; |
|||
image: string; |
|||
quantity: number; |
|||
addTime: number; |
|||
skuId?: number; // 新增: SKU ID |
|||
specInfo?: string; // 新增: 规格信息 |
|||
} |
|||
|
|||
// 订单商品项 |
|||
interface OrderGoodsItem { |
|||
goodsId: number; |
|||
quantity: number; |
|||
skuId?: number; // 新增: SKU ID |
|||
specInfo?: string; // 新增: 规格信息 |
|||
} |
|||
``` |
|||
|
|||
## 技术实现要点 |
|||
|
|||
### 1. 规格数据组织 |
|||
- 规格按 `specName` 分组 |
|||
- 规格值按 `specValue` 组织 |
|||
- SKU通过规格值字符串匹配 (`sku` 字段) |
|||
|
|||
### 2. SKU匹配算法 |
|||
```typescript |
|||
// 构建规格值字符串,按规格名称排序确保一致性 |
|||
const sortedSpecNames = specGroups.map(g => g.specName).sort(); |
|||
const specValues = sortedSpecNames.map(name => selectedSpecs[name]).join('|'); |
|||
const sku = skus.find(s => s.sku === specValues); |
|||
``` |
|||
|
|||
### 3. 购物车唯一性判断 |
|||
```typescript |
|||
// 根据goodsId和skuId判断是否为同一商品 |
|||
const existingItemIndex = newItems.findIndex(item => |
|||
item.goodsId === goods.goodsId && |
|||
(goods.skuId ? item.skuId === goods.skuId : !item.skuId) |
|||
); |
|||
``` |
|||
|
|||
## 需要后端配合的工作 |
|||
|
|||
### 1. API参数模型修改 🔄 |
|||
- `ShopGoodsSpecParam` 需要添加 `goodsId` 字段 |
|||
- `ShopGoodsSkuParam` 需要添加 `goodsId` 字段 |
|||
|
|||
### 2. 查询逻辑适配 🔄 |
|||
- 规格查询接口支持按商品ID过滤 |
|||
- SKU查询接口支持按商品ID过滤 |
|||
|
|||
### 3. 业务逻辑升级 🔄 |
|||
- 购物车接口支持SKU信息存储 |
|||
- 订单创建接口支持SKU信息处理 |
|||
- 库存扣减逻辑适配多规格 |
|||
- 价格计算逻辑适配多规格 |
|||
|
|||
## 测试验证 |
|||
|
|||
### 前端测试 ✅ |
|||
- [x] 商品详情页规格数据加载 |
|||
- [x] 规格选择器显示和交互 |
|||
- [x] SKU匹配和价格更新 |
|||
- [x] 购物车多规格商品支持 |
|||
- [x] 立即购买多规格商品支持 |
|||
|
|||
### 后端测试 🔄 |
|||
- [ ] API参数传递验证 |
|||
- [ ] 规格数据查询验证 |
|||
- [ ] SKU数据查询验证 |
|||
- [ ] 购物车SKU信息存储 |
|||
- [ ] 订单SKU信息处理 |
|||
|
|||
## 文档输出 |
|||
|
|||
1. **后端适配指南**: `docs/backend-multi-spec-integration.md` |
|||
- API接口修改要求 |
|||
- 数据库表结构检查 |
|||
- 业务逻辑适配建议 |
|||
- 测试场景和检查清单 |
|||
|
|||
2. **前端测试指南**: `docs/frontend-multi-spec-test.md` |
|||
- 功能测试步骤 |
|||
- 数据流验证方法 |
|||
- 常见问题排查 |
|||
- 调试技巧和优化建议 |
|||
|
|||
## 兼容性保证 |
|||
|
|||
### 向后兼容 |
|||
- 单规格商品功能完全保持不变 |
|||
- 现有购物车数据结构兼容 |
|||
- 现有订单流程不受影响 |
|||
|
|||
### 渐进增强 |
|||
- 多规格功能作为增强特性 |
|||
- 规格数据不存在时自动降级为单规格模式 |
|||
- 错误处理确保用户体验不受影响 |
|||
|
|||
## 下一步工作 |
|||
|
|||
### 短期 (1-2周) |
|||
1. 后端API适配完成 |
|||
2. 端到端测试验证 |
|||
3. 生产环境部署测试 |
|||
|
|||
### 中期 (1个月) |
|||
1. 性能优化和监控 |
|||
2. 用户反馈收集和改进 |
|||
3. 边界情况处理完善 |
|||
|
|||
### 长期 (3个月) |
|||
1. 规格图片支持 |
|||
2. 批量操作功能 |
|||
3. 高级规格管理功能 |
|||
|
|||
## 风险评估 |
|||
|
|||
### 低风险 ✅ |
|||
- 前端功能实现完整 |
|||
- 数据结构设计合理 |
|||
- 向后兼容性良好 |
|||
|
|||
### 中风险 ⚠️ |
|||
- 后端API适配工作量 |
|||
- 数据迁移和兼容性 |
|||
- 性能影响评估 |
|||
|
|||
### 缓解措施 |
|||
- 详细的后端适配文档 |
|||
- 完整的测试用例覆盖 |
|||
- 分阶段部署和验证 |
@ -0,0 +1,176 @@ |
|||
import React, { useState, useEffect } from 'react'; |
|||
import { View } from '@tarojs/components'; |
|||
import { Popup, Button, Radio, Image, Space, Cell, CellGroup } from '@nutui/nutui-react-taro'; |
|||
import { ShopGoodsSku } from '@/api/shop/shopGoodsSku/model'; |
|||
import { ShopGoodsSpec } from '@/api/shop/shopGoodsSpec/model'; |
|||
import { ShopGoods } from '@/api/shop/shopGoods/model'; |
|||
import './index.scss'; |
|||
|
|||
interface SpecSelectorProps { |
|||
visible?: boolean; |
|||
onClose: () => void; |
|||
goods: ShopGoods; |
|||
specs: ShopGoodsSpec[]; |
|||
skus: ShopGoodsSku[]; |
|||
onConfirm: (selectedSku: ShopGoodsSku, quantity: number, action?: 'cart' | 'buy') => void; |
|||
action?: 'cart' | 'buy'; |
|||
} |
|||
|
|||
interface SpecGroup { |
|||
specName: string; |
|||
values: string[]; |
|||
} |
|||
|
|||
const SpecSelector: React.FC<SpecSelectorProps> = ({ |
|||
visible = true, |
|||
onClose, |
|||
goods, |
|||
specs, |
|||
skus, |
|||
onConfirm, |
|||
action = 'cart' |
|||
}) => { |
|||
const [selectedSpecs, setSelectedSpecs] = useState<Record<string, string>>({}); |
|||
const [selectedSku, setSelectedSku] = useState<ShopGoodsSku | null>(null); |
|||
const [quantity, setQuantity] = useState(1); |
|||
const [specGroups, setSpecGroups] = useState<SpecGroup[]>([]); |
|||
|
|||
// 组织规格数据
|
|||
useEffect(() => { |
|||
if (specs.length > 0) { |
|||
const groups: Record<string, Set<string>> = {}; |
|||
|
|||
specs.forEach(spec => { |
|||
if (spec.specName && spec.specValue) { |
|||
if (!groups[spec.specName]) { |
|||
groups[spec.specName] = new Set(); |
|||
} |
|||
groups[spec.specName].add(spec.specValue); |
|||
} |
|||
}); |
|||
|
|||
const groupsArray = Object.entries(groups).map(([specName, values]) => ({ |
|||
specName, |
|||
values: Array.from(values) |
|||
})); |
|||
|
|||
setSpecGroups(groupsArray); |
|||
} |
|||
}, [specs]); |
|||
|
|||
// 根据选中规格找到对应SKU
|
|||
useEffect(() => { |
|||
if (Object.keys(selectedSpecs).length === specGroups.length && skus.length > 0) { |
|||
// 构建规格值字符串,按照规格名称排序确保一致性
|
|||
const sortedSpecNames = specGroups.map(g => g.specName).sort(); |
|||
const specValues = sortedSpecNames.map(name => selectedSpecs[name]).join('|'); |
|||
|
|||
const sku = skus.find(s => s.sku === specValues); |
|||
setSelectedSku(sku || null); |
|||
} else { |
|||
setSelectedSku(null); |
|||
} |
|||
}, [selectedSpecs, skus, specGroups]); |
|||
|
|||
// 选择规格值
|
|||
const handleSpecSelect = (specName: string, specValue: string) => { |
|||
setSelectedSpecs(prev => ({ |
|||
...prev, |
|||
[specName]: specValue |
|||
})); |
|||
}; |
|||
|
|||
// 确认选择
|
|||
const handleConfirm = () => { |
|||
if (!selectedSku) { |
|||
return; |
|||
} |
|||
onConfirm(selectedSku, quantity, action); |
|||
}; |
|||
|
|||
// 检查规格值是否可选(是否有对应的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; |
|||
}; |
|||
|
|||
return ( |
|||
<Popup |
|||
visible={visible} |
|||
position="bottom" |
|||
onClose={onClose} |
|||
style={{ height: '60vh' }} |
|||
> |
|||
<View className="spec-selector"> |
|||
{/* 商品信息 */} |
|||
<View className="spec-selector__header p-4"> |
|||
<Space className="flex"> |
|||
<Image |
|||
src={selectedSku?.image || goods.image || ''} |
|||
width="80" |
|||
height="80" |
|||
radius="8" |
|||
/> |
|||
<View className="goods-detail"> |
|||
<View className="goods-name font-medium text-lg">{goods.name}</View> |
|||
<View className="text-red-500"> |
|||
¥{selectedSku?.price || goods.price} |
|||
</View> |
|||
<View className="goods-stock text-gray-500"> |
|||
库存:{selectedSku?.stock || goods.stock} |
|||
</View> |
|||
</View> |
|||
</Space> |
|||
</View> |
|||
|
|||
{/* 规格选择 */} |
|||
<CellGroup className="spec-selector__content"> |
|||
<Cell> |
|||
<Space direction="vertical"> |
|||
<View className={'title'}>套餐</View> |
|||
<Radio.Group defaultValue="1" direction="horizontal"> |
|||
<Radio shape="button" value="1"> |
|||
选项1 |
|||
</Radio> |
|||
<Radio shape="button" value="2"> |
|||
选项2 |
|||
</Radio> |
|||
<Radio shape="button" value="3"> |
|||
选项3 |
|||
</Radio> |
|||
</Radio.Group> |
|||
</Space> |
|||
</Cell> |
|||
</CellGroup> |
|||
{/* 底部按钮 */} |
|||
<View className="fixed bottom-7 w-full"> |
|||
<View className={'px-4'}> |
|||
<Button |
|||
type="success" |
|||
size="large" |
|||
className={'w-full'} |
|||
block |
|||
// disabled={!selectedSku || !selectedSku.stock || selectedSku.stock <= 0}
|
|||
onClick={handleConfirm} |
|||
> |
|||
确定 |
|||
</Button> |
|||
</View> |
|||
</View> |
|||
</View> |
|||
</Popup> |
|||
); |
|||
}; |
|||
|
|||
export default SpecSelector; |
Loading…
Reference in new issue