18 changed files with 8443 additions and 360 deletions
@ -0,0 +1,245 @@ |
|||||
|
# 前端订单提交实现文档 |
||||
|
|
||||
|
## 概述 |
||||
|
|
||||
|
本文档描述了前端订单提交的完整实现,包括单商品下单、购物车批量下单等场景。 |
||||
|
|
||||
|
## 核心改进 |
||||
|
|
||||
|
### 1. 统一的API接口 |
||||
|
|
||||
|
**新的订单创建接口:** |
||||
|
```typescript |
||||
|
// 订单商品项 |
||||
|
interface OrderGoodsItem { |
||||
|
goodsId: number; |
||||
|
quantity: number; |
||||
|
skuId?: number; |
||||
|
specInfo?: string; |
||||
|
} |
||||
|
|
||||
|
// 创建订单请求 |
||||
|
interface OrderCreateRequest { |
||||
|
goodsItems: OrderGoodsItem[]; |
||||
|
addressId?: number; |
||||
|
payType: number; |
||||
|
couponId?: number; |
||||
|
comments?: string; |
||||
|
deliveryType?: number; |
||||
|
selfTakeMerchantId?: number; |
||||
|
title?: string; |
||||
|
} |
||||
|
|
||||
|
// 微信支付返回数据 |
||||
|
interface WxPayResult { |
||||
|
prepayId: string; |
||||
|
orderNo: string; |
||||
|
timeStamp: string; |
||||
|
nonceStr: string; |
||||
|
package: string; |
||||
|
signType: string; |
||||
|
paySign: string; |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 2. 标题长度限制 |
||||
|
|
||||
|
**工具函数:** |
||||
|
```typescript |
||||
|
// 截取文本,限制长度 |
||||
|
export function truncateText(text: string, maxLength: number = 30): string { |
||||
|
if (!text) return ''; |
||||
|
if (text.length <= maxLength) return text; |
||||
|
return text.substring(0, maxLength); |
||||
|
} |
||||
|
|
||||
|
// 生成订单标题 |
||||
|
export function generateOrderTitle(goodsNames: string[], maxLength: number = 30): string { |
||||
|
if (!goodsNames || goodsNames.length === 0) return '商品订单'; |
||||
|
|
||||
|
let title = goodsNames.length === 1 |
||||
|
? goodsNames[0] |
||||
|
: `${goodsNames[0]}等${goodsNames.length}件商品`; |
||||
|
|
||||
|
return truncateText(title, maxLength); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 实现细节 |
||||
|
|
||||
|
### 1. 单商品下单 |
||||
|
|
||||
|
**文件:** `src/shop/orderConfirm/index.tsx` |
||||
|
|
||||
|
**核心逻辑:** |
||||
|
```typescript |
||||
|
const onWxPay = async (goods: ShopGoods) => { |
||||
|
// 1. 校验收货地址 |
||||
|
if (!address) { |
||||
|
Taro.showToast({ title: '请选择收货地址', icon: 'error' }); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
Taro.showLoading({title: '支付中...'}); |
||||
|
|
||||
|
try { |
||||
|
// 2. 构建订单数据 |
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems: [{ goodsId: goods.goodsId!, quantity: 1 }], |
||||
|
addressId: address.id, |
||||
|
payType: 1, |
||||
|
comments: goods.name, |
||||
|
deliveryType: 0 |
||||
|
}; |
||||
|
|
||||
|
// 3. 创建订单 |
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
// 4. 微信支付 |
||||
|
if (result && result.prepayId) { |
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType, |
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
|
||||
|
// 5. 支付成功处理 |
||||
|
Taro.showToast({ title: '支付成功', icon: 'success' }); |
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({url: '/pages/order/order'}); |
||||
|
}, 2000); |
||||
|
} |
||||
|
} catch (error: any) { |
||||
|
Taro.showToast({ title: error.message || '下单失败', icon: 'error' }); |
||||
|
} finally { |
||||
|
Taro.hideLoading(); |
||||
|
} |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 2. 购物车批量下单 |
||||
|
|
||||
|
**文件:** `src/shop/orderConfirmCart/index.tsx` |
||||
|
|
||||
|
**核心逻辑:** |
||||
|
```typescript |
||||
|
const onCartPay = async () => { |
||||
|
// 1. 校验 |
||||
|
if (!address || !cartItems || cartItems.length === 0) { |
||||
|
// 错误处理 |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
try { |
||||
|
// 2. 构建批量商品数据 |
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems: cartItems.map(item => ({ |
||||
|
goodsId: item.goodsId!, |
||||
|
quantity: item.quantity || 1 |
||||
|
})), |
||||
|
addressId: address.id, |
||||
|
payType: 1, |
||||
|
comments: '购物车下单', |
||||
|
deliveryType: 0 |
||||
|
}; |
||||
|
|
||||
|
// 3. 创建订单并支付 |
||||
|
const result = await createOrder(orderData); |
||||
|
// ... 支付逻辑 |
||||
|
} catch (error) { |
||||
|
// 错误处理 |
||||
|
} |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
## 数据流程 |
||||
|
|
||||
|
### 1. 前端提交流程 |
||||
|
|
||||
|
``` |
||||
|
用户点击支付 |
||||
|
↓ |
||||
|
校验地址和商品 |
||||
|
↓ |
||||
|
构建OrderCreateRequest |
||||
|
↓ |
||||
|
调用createOrder API |
||||
|
↓ |
||||
|
后端返回WxPayResult |
||||
|
↓ |
||||
|
调用微信支付 |
||||
|
↓ |
||||
|
支付成功跳转 |
||||
|
``` |
||||
|
|
||||
|
### 2. 后端处理流程 |
||||
|
|
||||
|
``` |
||||
|
接收OrderCreateRequest |
||||
|
↓ |
||||
|
参数校验 |
||||
|
↓ |
||||
|
构建订单主表 |
||||
|
↓ |
||||
|
保存订单商品明细 |
||||
|
↓ |
||||
|
库存扣减 |
||||
|
↓ |
||||
|
生成订单标题(≤30字) |
||||
|
↓ |
||||
|
创建微信支付 |
||||
|
↓ |
||||
|
返回支付参数 |
||||
|
``` |
||||
|
|
||||
|
## 关键特性 |
||||
|
|
||||
|
### 1. 数据安全 |
||||
|
- 前端只传递商品ID和数量 |
||||
|
- 价格、库存等敏感信息由后端实时获取 |
||||
|
- 防止前端数据篡改 |
||||
|
|
||||
|
### 2. 业务完整性 |
||||
|
- 统一的订单创建流程 |
||||
|
- 完整的错误处理机制 |
||||
|
- 支持多种下单场景 |
||||
|
|
||||
|
### 3. 用户体验 |
||||
|
- 清晰的加载状态 |
||||
|
- 友好的错误提示 |
||||
|
- 自动跳转到订单页面 |
||||
|
|
||||
|
## 扩展功能 |
||||
|
|
||||
|
### 1. 支持的下单类型 |
||||
|
- 单商品立即购买 |
||||
|
- 购物车批量下单 |
||||
|
- 自提订单 |
||||
|
- 使用优惠券下单 |
||||
|
|
||||
|
### 2. 支持的配送方式 |
||||
|
- 快递配送 (deliveryType: 0) |
||||
|
- 到店自提 (deliveryType: 1) |
||||
|
|
||||
|
### 3. 支持的支付方式 |
||||
|
- 微信支付 (payType: 1) |
||||
|
- 余额支付 (payType: 0) |
||||
|
- 其他支付方式... |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **标题长度限制**:订单标题最多30个汉字,超过自动截取 |
||||
|
2. **库存校验**:后端会实时校验商品库存 |
||||
|
3. **地址校验**:确保收货地址属于当前用户 |
||||
|
4. **错误处理**:完善的异常捕获和用户提示 |
||||
|
5. **支付安全**:支付参数由后端生成,前端不可篡改 |
||||
|
|
||||
|
## 测试建议 |
||||
|
|
||||
|
1. 测试单商品下单流程 |
||||
|
2. 测试购物车批量下单 |
||||
|
3. 测试各种异常情况(库存不足、地址无效等) |
||||
|
4. 测试支付成功和失败的处理 |
||||
|
5. 测试订单标题长度限制功能 |
@ -0,0 +1,264 @@ |
|||||
|
# 支付逻辑重构指南 |
||||
|
|
||||
|
## 概述 |
||||
|
|
||||
|
本文档描述了支付逻辑的重构过程,将原本分散的支付代码统一整合,提高了代码的可维护性和复用性。 |
||||
|
|
||||
|
## 重构前后对比 |
||||
|
|
||||
|
### 重构前的问题 |
||||
|
|
||||
|
1. **代码重复**:每个支付方式都有重复的订单构建逻辑 |
||||
|
2. **维护困难**:支付逻辑分散在多个方法中 |
||||
|
3. **扩展性差**:添加新的支付方式需要修改多处代码 |
||||
|
|
||||
|
### 重构后的优势 |
||||
|
|
||||
|
1. **统一入口**:所有支付都通过 `onPay` 方法处理 |
||||
|
2. **代码复用**:订单构建逻辑统一封装 |
||||
|
3. **易于扩展**:新增支付方式只需在工具类中添加 |
||||
|
4. **错误处理统一**:所有支付的错误处理逻辑一致 |
||||
|
|
||||
|
## 核心改进 |
||||
|
|
||||
|
### 1. 统一的支付工具类 |
||||
|
|
||||
|
**文件:** `src/utils/payment.ts` |
||||
|
|
||||
|
```typescript |
||||
|
// 支付类型枚举 |
||||
|
export enum PaymentType { |
||||
|
BALANCE = 0, // 余额支付 |
||||
|
WECHAT = 1, // 微信支付 |
||||
|
ALIPAY = 3, // 支付宝支付 |
||||
|
} |
||||
|
|
||||
|
// 统一支付处理类 |
||||
|
export class PaymentHandler { |
||||
|
static async pay( |
||||
|
orderData: OrderCreateRequest, |
||||
|
paymentType: PaymentType, |
||||
|
callback?: PaymentCallback |
||||
|
): Promise<void> { |
||||
|
// 统一的支付处理逻辑 |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 2. 订单数据构建函数 |
||||
|
|
||||
|
```typescript |
||||
|
// 单商品订单 |
||||
|
export function buildSingleGoodsOrder( |
||||
|
goodsId: number, |
||||
|
quantity: number = 1, |
||||
|
addressId?: number, |
||||
|
options?: { |
||||
|
comments?: string; |
||||
|
deliveryType?: number; |
||||
|
couponId?: number; |
||||
|
} |
||||
|
): OrderCreateRequest |
||||
|
|
||||
|
// 购物车订单 |
||||
|
export function buildCartOrder( |
||||
|
cartItems: Array<{ goodsId: number; quantity: number }>, |
||||
|
addressId?: number, |
||||
|
options?: { ... } |
||||
|
): OrderCreateRequest |
||||
|
``` |
||||
|
|
||||
|
### 3. 简化的支付入口 |
||||
|
|
||||
|
**重构前:** |
||||
|
```typescript |
||||
|
const onWxPay = async (goods: ShopGoods) => { |
||||
|
// 校验逻辑 |
||||
|
// 构建订单数据 |
||||
|
// 调用创建订单API |
||||
|
// 处理微信支付 |
||||
|
// 错误处理 |
||||
|
} |
||||
|
|
||||
|
const onBalancePay = async (goods: ShopGoods) => { |
||||
|
// 重复的校验逻辑 |
||||
|
// 重复的订单构建逻辑 |
||||
|
// 处理余额支付 |
||||
|
// 重复的错误处理 |
||||
|
} |
||||
|
|
||||
|
const onPay = async (goods: ShopGoods) => { |
||||
|
if (payment?.type == 0) { |
||||
|
await onBalancePay(goods) |
||||
|
} |
||||
|
if (payment?.type == 1) { |
||||
|
await onWxPay(goods) |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
**重构后:** |
||||
|
```typescript |
||||
|
const onPay = async (goods: ShopGoods) => { |
||||
|
// 基础校验 |
||||
|
if (!address || !payment) { |
||||
|
// 错误提示 |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 构建订单数据 |
||||
|
const orderData = buildSingleGoodsOrder( |
||||
|
goods.goodsId!, |
||||
|
1, |
||||
|
address.id, |
||||
|
{ comments: goods.name } |
||||
|
); |
||||
|
|
||||
|
// 选择支付类型 |
||||
|
const paymentType = payment.type === 0 ? PaymentType.BALANCE : PaymentType.WECHAT; |
||||
|
|
||||
|
// 执行支付 |
||||
|
await PaymentHandler.pay(orderData, paymentType); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
## 使用示例 |
||||
|
|
||||
|
### 1. 单商品下单 |
||||
|
|
||||
|
```typescript |
||||
|
// 在 orderConfirm/index.tsx 中 |
||||
|
const onPay = async (goods: ShopGoods) => { |
||||
|
if (!address || !payment) return; |
||||
|
|
||||
|
const orderData = buildSingleGoodsOrder( |
||||
|
goods.goodsId!, |
||||
|
1, |
||||
|
address.id, |
||||
|
{ |
||||
|
comments: goods.name, |
||||
|
deliveryType: 0 |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
const paymentType = payment.type === 0 ? PaymentType.BALANCE : PaymentType.WECHAT; |
||||
|
await PaymentHandler.pay(orderData, paymentType); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 2. 购物车批量下单 |
||||
|
|
||||
|
```typescript |
||||
|
// 在 orderConfirmCart/index.tsx 中 |
||||
|
const onPay = async () => { |
||||
|
if (!address || !cartItems?.length) return; |
||||
|
|
||||
|
const orderData = buildCartOrder( |
||||
|
cartItems.map(item => ({ |
||||
|
goodsId: item.goodsId!, |
||||
|
quantity: item.quantity || 1 |
||||
|
})), |
||||
|
address.id, |
||||
|
{ |
||||
|
comments: '购物车下单', |
||||
|
deliveryType: 0 |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
const paymentType = payment?.type === 0 ? PaymentType.BALANCE : PaymentType.WECHAT; |
||||
|
await PaymentHandler.pay(orderData, paymentType); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 3. 使用优惠券下单 |
||||
|
|
||||
|
```typescript |
||||
|
const onPayWithCoupon = async (goods: ShopGoods, couponId: number) => { |
||||
|
const orderData = buildSingleGoodsOrder( |
||||
|
goods.goodsId!, |
||||
|
1, |
||||
|
address.id, |
||||
|
{ |
||||
|
comments: `使用优惠券购买${goods.name}`, |
||||
|
couponId: couponId |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
await PaymentHandler.pay(orderData, PaymentType.WECHAT); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
### 4. 自提订单 |
||||
|
|
||||
|
```typescript |
||||
|
const onSelfPickupOrder = async (goods: ShopGoods, merchantId: number) => { |
||||
|
const orderData = buildSingleGoodsOrder( |
||||
|
goods.goodsId!, |
||||
|
1, |
||||
|
address.id, |
||||
|
{ |
||||
|
comments: `自提订单 - ${goods.name}`, |
||||
|
deliveryType: 1, |
||||
|
selfTakeMerchantId: merchantId |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
await PaymentHandler.pay(orderData, PaymentType.WECHAT); |
||||
|
}; |
||||
|
``` |
||||
|
|
||||
|
## 扩展新的支付方式 |
||||
|
|
||||
|
### 1. 添加支付类型 |
||||
|
|
||||
|
```typescript |
||||
|
// 在 PaymentType 枚举中添加 |
||||
|
export enum PaymentType { |
||||
|
BALANCE = 0, |
||||
|
WECHAT = 1, |
||||
|
ALIPAY = 3, |
||||
|
UNIONPAY = 4, // 新增银联支付 |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 2. 实现支付处理方法 |
||||
|
|
||||
|
```typescript |
||||
|
// 在 PaymentHandler 类中添加 |
||||
|
private static async handleUnionPay(result: any): Promise<void> { |
||||
|
// 银联支付逻辑 |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### 3. 在支付分发中添加 |
||||
|
|
||||
|
```typescript |
||||
|
// 在 PaymentHandler.pay 方法中添加 |
||||
|
switch (paymentType) { |
||||
|
case PaymentType.WECHAT: |
||||
|
await this.handleWechatPay(result); |
||||
|
break; |
||||
|
case PaymentType.BALANCE: |
||||
|
await this.handleBalancePay(result); |
||||
|
break; |
||||
|
case PaymentType.UNIONPAY: // 新增 |
||||
|
await this.handleUnionPay(result); |
||||
|
break; |
||||
|
// ... |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## 优势总结 |
||||
|
|
||||
|
1. **代码简洁**:支付入口方法从 50+ 行减少到 20+ 行 |
||||
|
2. **逻辑清晰**:订单构建、支付处理、错误处理分离 |
||||
|
3. **易于测试**:每个功能模块独立,便于单元测试 |
||||
|
4. **维护性强**:修改支付逻辑只需在工具类中修改 |
||||
|
5. **扩展性好**:新增支付方式无需修改业务代码 |
||||
|
|
||||
|
## 注意事项 |
||||
|
|
||||
|
1. **向后兼容**:确保重构后的接口与原有调用方式兼容 |
||||
|
2. **错误处理**:统一的错误处理机制,确保用户体验一致 |
||||
|
3. **类型安全**:使用 TypeScript 枚举确保支付类型的类型安全 |
||||
|
4. **测试覆盖**:对重构后的代码进行充分的测试 |
@ -0,0 +1,248 @@ |
|||||
|
/** |
||||
|
* 订单服务实现类示例 |
||||
|
* 展示如何保存订单商品信息的业务逻辑 |
||||
|
*/ |
||||
|
@Service |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public class ShopOrderServiceImpl implements ShopOrderService { |
||||
|
|
||||
|
@Autowired |
||||
|
private ShopOrderMapper shopOrderMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private OrderGoodsMapper orderGoodsMapper; |
||||
|
|
||||
|
@Autowired |
||||
|
private ShopGoodsService shopGoodsService; |
||||
|
|
||||
|
@Autowired |
||||
|
private ShopUserAddressService addressService; |
||||
|
|
||||
|
@Autowired |
||||
|
private WxPayService wxPayService; |
||||
|
|
||||
|
/** |
||||
|
* 创建订单 |
||||
|
*/ |
||||
|
@Override |
||||
|
@Transactional(rollbackFor = Exception.class) |
||||
|
public Map<String, String> createOrder(OrderCreateRequest request, User loginUser) { |
||||
|
// 1. 参数校验
|
||||
|
validateOrderRequest(request, loginUser); |
||||
|
|
||||
|
// 2. 构建订单对象
|
||||
|
ShopOrder shopOrder = buildShopOrder(request, loginUser); |
||||
|
|
||||
|
// 3. 应用业务规则
|
||||
|
applyBusinessRules(shopOrder, loginUser); |
||||
|
|
||||
|
// 4. 保存订单主表
|
||||
|
boolean saved = shopOrderMapper.insert(shopOrder) > 0; |
||||
|
if (!saved) { |
||||
|
throw new BusinessException("订单保存失败"); |
||||
|
} |
||||
|
|
||||
|
// 5. 保存订单商品明细 - 核心业务逻辑
|
||||
|
saveOrderGoods(shopOrder, request.getGoodsItems()); |
||||
|
|
||||
|
// 6. 创建微信支付订单
|
||||
|
try { |
||||
|
return wxPayService.createWxOrder(shopOrder); |
||||
|
} catch (Exception e) { |
||||
|
log.error("创建微信支付订单失败,订单号:{}", shopOrder.getOrderNo(), e); |
||||
|
throw new BusinessException("创建支付订单失败:" + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 保存订单商品明细 - 核心实现 |
||||
|
*/ |
||||
|
private void saveOrderGoods(ShopOrder shopOrder, List<OrderGoodsItem> goodsItems) { |
||||
|
List<OrderGoods> orderGoodsList = new ArrayList<>(); |
||||
|
BigDecimal totalPrice = BigDecimal.ZERO; |
||||
|
int totalQuantity = 0; |
||||
|
List<String> goodsNames = new ArrayList<>(); |
||||
|
|
||||
|
for (OrderGoodsItem item : goodsItems) { |
||||
|
// 1. 获取商品最新信息进行校验
|
||||
|
ShopGoods goods = shopGoodsService.getById(item.getGoodsId()); |
||||
|
if (goods == null) { |
||||
|
throw new BusinessException("商品不存在:" + item.getGoodsId()); |
||||
|
} |
||||
|
|
||||
|
// 2. 商品状态校验
|
||||
|
if (goods.getIsShow() != 1) { |
||||
|
throw new BusinessException("商品已下架:" + goods.getName()); |
||||
|
} |
||||
|
|
||||
|
// 3. 库存校验
|
||||
|
if (goods.getStock() < item.getQuantity()) { |
||||
|
throw new BusinessException("商品库存不足:" + goods.getName()); |
||||
|
} |
||||
|
|
||||
|
// 4. 价格计算(以数据库中的价格为准)
|
||||
|
BigDecimal itemPrice = new BigDecimal(goods.getPrice()); |
||||
|
BigDecimal itemTotalPrice = itemPrice.multiply(new BigDecimal(item.getQuantity())); |
||||
|
|
||||
|
// 5. 构建订单商品记录
|
||||
|
OrderGoods orderGoods = new OrderGoods(); |
||||
|
orderGoods.setOrderId(shopOrder.getOrderId()); |
||||
|
orderGoods.setGoodsId(item.getGoodsId()); |
||||
|
orderGoods.setTotalNum(item.getQuantity()); |
||||
|
orderGoods.setPayPrice(itemTotalPrice.toString()); |
||||
|
orderGoods.setType(0); // 0商城
|
||||
|
orderGoods.setPayStatus("0"); // 0未付款
|
||||
|
orderGoods.setOrderStatus(0); // 0未完成
|
||||
|
orderGoods.setUserId(shopOrder.getUserId()); |
||||
|
orderGoods.setTenantId(shopOrder.getTenantId()); |
||||
|
orderGoods.setCreateTime(LocalDateTime.now()); |
||||
|
|
||||
|
// 6. SKU信息处理(如果有规格)
|
||||
|
if (item.getSkuId() != null) { |
||||
|
// 处理SKU相关逻辑
|
||||
|
// orderGoods.setSkuId(item.getSkuId());
|
||||
|
// orderGoods.setSpecInfo(item.getSpecInfo());
|
||||
|
} |
||||
|
|
||||
|
orderGoodsList.add(orderGoods); |
||||
|
|
||||
|
// 7. 累计计算
|
||||
|
totalPrice = totalPrice.add(itemTotalPrice); |
||||
|
totalQuantity += item.getQuantity(); |
||||
|
goodsNames.add(goods.getName()); |
||||
|
|
||||
|
// 8. 扣减库存(根据业务需求,可能在支付成功后扣减)
|
||||
|
if (goods.getDeductStockType() == 10) { // 10下单减库存
|
||||
|
goods.setStock(goods.getStock() - item.getQuantity()); |
||||
|
shopGoodsService.updateById(goods); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 9. 批量保存订单商品
|
||||
|
if (!orderGoodsList.isEmpty()) { |
||||
|
orderGoodsMapper.insertBatch(orderGoodsList); |
||||
|
} |
||||
|
|
||||
|
// 10. 更新订单总价和数量
|
||||
|
shopOrder.setTotalPrice(totalPrice.toString()); |
||||
|
shopOrder.setPayPrice(totalPrice.toString()); // 暂时不考虑优惠
|
||||
|
shopOrder.setTotalNum(totalQuantity); |
||||
|
|
||||
|
// 11. 生成订单标题(限制30个汉字)
|
||||
|
String title = generateOrderTitle(goodsNames); |
||||
|
shopOrder.setTitle(title); |
||||
|
|
||||
|
// 12. 更新订单主表
|
||||
|
shopOrderMapper.updateById(shopOrder); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成订单标题,限制长度不超过30个汉字 |
||||
|
*/ |
||||
|
private String generateOrderTitle(List<String> goodsNames) { |
||||
|
if (goodsNames.isEmpty()) { |
||||
|
return "商品订单"; |
||||
|
} |
||||
|
|
||||
|
String title; |
||||
|
if (goodsNames.size() == 1) { |
||||
|
title = goodsNames.get(0); |
||||
|
} else { |
||||
|
title = goodsNames.get(0) + "等" + goodsNames.size() + "件商品"; |
||||
|
} |
||||
|
|
||||
|
// 限制标题长度最多30个汉字
|
||||
|
if (title.length() > 30) { |
||||
|
title = title.substring(0, 30); |
||||
|
} |
||||
|
|
||||
|
return title; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 参数校验 |
||||
|
*/ |
||||
|
private void validateOrderRequest(OrderCreateRequest request, User loginUser) { |
||||
|
if (request.getGoodsItems() == null || request.getGoodsItems().isEmpty()) { |
||||
|
throw new BusinessException("商品信息不能为空"); |
||||
|
} |
||||
|
|
||||
|
if (request.getAddressId() == null) { |
||||
|
throw new BusinessException("收货地址不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 校验收货地址是否属于当前用户
|
||||
|
ShopUserAddress address = addressService.getById(request.getAddressId()); |
||||
|
if (address == null || !address.getUserId().equals(loginUser.getUserId())) { |
||||
|
throw new BusinessException("收货地址不存在或不属于当前用户"); |
||||
|
} |
||||
|
|
||||
|
// 校验商品数量
|
||||
|
for (OrderGoodsItem item : request.getGoodsItems()) { |
||||
|
if (item.getGoodsId() == null || item.getQuantity() <= 0) { |
||||
|
throw new BusinessException("商品信息不正确"); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构建订单对象 |
||||
|
*/ |
||||
|
private ShopOrder buildShopOrder(OrderCreateRequest request, User loginUser) { |
||||
|
ShopOrder shopOrder = new ShopOrder(); |
||||
|
|
||||
|
// 基础信息
|
||||
|
shopOrder.setOrderNo(generateOrderNo()); |
||||
|
shopOrder.setType(0); // 0商城订单
|
||||
|
shopOrder.setChannel(0); // 0小程序
|
||||
|
shopOrder.setUserId(loginUser.getUserId()); |
||||
|
shopOrder.setTenantId(loginUser.getTenantId()); |
||||
|
|
||||
|
// 用户信息
|
||||
|
shopOrder.setRealName(loginUser.getRealName()); |
||||
|
shopOrder.setPhone(loginUser.getPhone()); |
||||
|
|
||||
|
// 地址信息
|
||||
|
ShopUserAddress address = addressService.getById(request.getAddressId()); |
||||
|
shopOrder.setAddressId(request.getAddressId()); |
||||
|
shopOrder.setAddress(address.getProvince() + address.getCity() + |
||||
|
address.getRegion() + address.getAddress()); |
||||
|
|
||||
|
// 支付信息
|
||||
|
shopOrder.setPayType(request.getPayType()); |
||||
|
shopOrder.setPayStatus(0); // 0未付款
|
||||
|
shopOrder.setOrderStatus(0); // 0未使用
|
||||
|
|
||||
|
// 配送信息
|
||||
|
shopOrder.setDeliveryType(request.getDeliveryType()); |
||||
|
if (request.getSelfTakeMerchantId() != null) { |
||||
|
shopOrder.setSelfTakeMerchantId(request.getSelfTakeMerchantId()); |
||||
|
} |
||||
|
|
||||
|
// 其他信息
|
||||
|
shopOrder.setComments(request.getComments()); |
||||
|
shopOrder.setCreateTime(LocalDateTime.now()); |
||||
|
|
||||
|
return shopOrder; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 应用业务规则 |
||||
|
*/ |
||||
|
private void applyBusinessRules(ShopOrder shopOrder, User loginUser) { |
||||
|
// 设置默认标题(如果没有设置)
|
||||
|
if (shopOrder.getTitle() == null) { |
||||
|
shopOrder.setTitle("商品订单"); |
||||
|
} |
||||
|
|
||||
|
// 其他业务规则...
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 生成订单号 |
||||
|
*/ |
||||
|
private String generateOrderNo() { |
||||
|
return "SO" + System.currentTimeMillis() + |
||||
|
String.format("%04d", new Random().nextInt(10000)); |
||||
|
} |
||||
|
} |
@ -0,0 +1,317 @@ |
|||||
|
/** |
||||
|
* 前端订单提交完整示例 |
||||
|
* 展示如何使用新的订单API进行下单 |
||||
|
*/ |
||||
|
import React, { useState, useEffect } from 'react'; |
||||
|
import Taro from '@tarojs/taro'; |
||||
|
import { Button } from '@nutui/nutui-react-taro'; |
||||
|
import { createOrder } from '@/api/shop/shopOrder'; |
||||
|
import { OrderCreateRequest, OrderGoodsItem } from '@/api/shop/shopOrder/model'; |
||||
|
import { ShopGoods } from '@/api/shop/shopGoods/model'; |
||||
|
import { ShopUserAddress } from '@/api/shop/shopUserAddress/model'; |
||||
|
import { generateOrderTitle } from '@/utils/common'; |
||||
|
|
||||
|
interface OrderExampleProps { |
||||
|
goods: ShopGoods; |
||||
|
address: ShopUserAddress; |
||||
|
quantity?: number; |
||||
|
} |
||||
|
|
||||
|
const OrderExample: React.FC<OrderExampleProps> = ({ |
||||
|
goods, |
||||
|
address, |
||||
|
quantity = 1 |
||||
|
}) => { |
||||
|
const [loading, setLoading] = useState(false); |
||||
|
|
||||
|
/** |
||||
|
* 单商品下单示例 |
||||
|
*/ |
||||
|
const handleSingleGoodsOrder = async () => { |
||||
|
if (!address) { |
||||
|
Taro.showToast({ |
||||
|
title: '请选择收货地址', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
setLoading(true); |
||||
|
|
||||
|
try { |
||||
|
// 1. 构建订单请求数据
|
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems: [ |
||||
|
{ |
||||
|
goodsId: goods.goodsId!, |
||||
|
quantity: quantity |
||||
|
} |
||||
|
], |
||||
|
addressId: address.id, |
||||
|
payType: 1, // 微信支付
|
||||
|
comments: `购买${goods.name}`, |
||||
|
deliveryType: 0, // 快递配送
|
||||
|
// 可选:自定义订单标题
|
||||
|
title: generateOrderTitle([goods.name!]) |
||||
|
}; |
||||
|
|
||||
|
// 2. 调用创建订单API
|
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
if (result && result.prepayId) { |
||||
|
// 3. 调用微信支付
|
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType, |
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
|
||||
|
// 4. 支付成功处理
|
||||
|
Taro.showToast({ |
||||
|
title: '支付成功', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({url: '/pages/order/order'}); |
||||
|
}, 2000); |
||||
|
} |
||||
|
} catch (error: any) { |
||||
|
console.error('下单失败:', error); |
||||
|
Taro.showToast({ |
||||
|
title: error.message || '下单失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} finally { |
||||
|
setLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 购物车批量下单示例 |
||||
|
*/ |
||||
|
const handleCartOrder = async (cartItems: Array<{goodsId: number, quantity: number, goodsName: string}>) => { |
||||
|
if (!address) { |
||||
|
Taro.showToast({ |
||||
|
title: '请选择收货地址', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (!cartItems || cartItems.length === 0) { |
||||
|
Taro.showToast({ |
||||
|
title: '购物车为空', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
setLoading(true); |
||||
|
|
||||
|
try { |
||||
|
// 1. 构建订单商品列表
|
||||
|
const goodsItems: OrderGoodsItem[] = cartItems.map(item => ({ |
||||
|
goodsId: item.goodsId, |
||||
|
quantity: item.quantity |
||||
|
})); |
||||
|
|
||||
|
// 2. 生成订单标题
|
||||
|
const goodsNames = cartItems.map(item => item.goodsName); |
||||
|
const orderTitle = generateOrderTitle(goodsNames); |
||||
|
|
||||
|
// 3. 构建订单请求数据
|
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems, |
||||
|
addressId: address.id, |
||||
|
payType: 1, // 微信支付
|
||||
|
comments: '购物车下单', |
||||
|
deliveryType: 0, // 快递配送
|
||||
|
title: orderTitle |
||||
|
}; |
||||
|
|
||||
|
// 4. 调用创建订单API
|
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
if (result && result.prepayId) { |
||||
|
// 5. 调用微信支付
|
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType, |
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
|
||||
|
// 6. 支付成功处理
|
||||
|
Taro.showToast({ |
||||
|
title: '支付成功', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
|
||||
|
// 7. 清空购物车(可选)
|
||||
|
// clearCart();
|
||||
|
|
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({url: '/pages/order/order'}); |
||||
|
}, 2000); |
||||
|
} |
||||
|
} catch (error: any) { |
||||
|
console.error('下单失败:', error); |
||||
|
Taro.showToast({ |
||||
|
title: error.message || '下单失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} finally { |
||||
|
setLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 自提订单示例 |
||||
|
*/ |
||||
|
const handleSelfPickupOrder = async (merchantId: number) => { |
||||
|
setLoading(true); |
||||
|
|
||||
|
try { |
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems: [ |
||||
|
{ |
||||
|
goodsId: goods.goodsId!, |
||||
|
quantity: quantity |
||||
|
} |
||||
|
], |
||||
|
addressId: address.id, |
||||
|
payType: 1, |
||||
|
deliveryType: 1, // 自提
|
||||
|
selfTakeMerchantId: merchantId, |
||||
|
comments: `自提订单 - ${goods.name}`, |
||||
|
title: generateOrderTitle([goods.name!]) |
||||
|
}; |
||||
|
|
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
if (result && result.prepayId) { |
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType, |
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
|
||||
|
Taro.showToast({ |
||||
|
title: '下单成功,请到店自提', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({url: '/pages/order/order'}); |
||||
|
}, 2000); |
||||
|
} |
||||
|
} catch (error: any) { |
||||
|
console.error('下单失败:', error); |
||||
|
Taro.showToast({ |
||||
|
title: error.message || '下单失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} finally { |
||||
|
setLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 使用优惠券下单示例 |
||||
|
*/ |
||||
|
const handleOrderWithCoupon = async (couponId: number) => { |
||||
|
setLoading(true); |
||||
|
|
||||
|
try { |
||||
|
const orderData: OrderCreateRequest = { |
||||
|
goodsItems: [ |
||||
|
{ |
||||
|
goodsId: goods.goodsId!, |
||||
|
quantity: quantity |
||||
|
} |
||||
|
], |
||||
|
addressId: address.id, |
||||
|
payType: 1, |
||||
|
couponId: couponId, // 使用优惠券
|
||||
|
deliveryType: 0, |
||||
|
comments: `使用优惠券购买${goods.name}`, |
||||
|
title: generateOrderTitle([goods.name!]) |
||||
|
}; |
||||
|
|
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
if (result && result.prepayId) { |
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType, |
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
|
||||
|
Taro.showToast({ |
||||
|
title: '支付成功', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
|
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({url: '/pages/order/order'}); |
||||
|
}, 2000); |
||||
|
} |
||||
|
} catch (error: any) { |
||||
|
console.error('下单失败:', error); |
||||
|
Taro.showToast({ |
||||
|
title: error.message || '下单失败', |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
} finally { |
||||
|
setLoading(false); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
return ( |
||||
|
<div> |
||||
|
<Button |
||||
|
type="primary" |
||||
|
loading={loading} |
||||
|
onClick={handleSingleGoodsOrder} |
||||
|
> |
||||
|
立即购买 |
||||
|
</Button> |
||||
|
|
||||
|
<Button |
||||
|
type="success" |
||||
|
loading={loading} |
||||
|
onClick={() => handleCartOrder([ |
||||
|
{goodsId: goods.goodsId!, quantity: 1, goodsName: goods.name!} |
||||
|
])} |
||||
|
> |
||||
|
购物车下单 |
||||
|
</Button> |
||||
|
|
||||
|
<Button |
||||
|
type="warning" |
||||
|
loading={loading} |
||||
|
onClick={() => handleSelfPickupOrder(1)} |
||||
|
> |
||||
|
自提下单 |
||||
|
</Button> |
||||
|
|
||||
|
<Button |
||||
|
type="info" |
||||
|
loading={loading} |
||||
|
onClick={() => handleOrderWithCoupon(123)} |
||||
|
> |
||||
|
使用优惠券下单 |
||||
|
</Button> |
||||
|
</div> |
||||
|
); |
||||
|
}; |
||||
|
|
||||
|
export default OrderExample; |
@ -0,0 +1 @@ |
|||||
|
import '@tarojs/rn-supporter/entry-file.js' |
@ -0,0 +1,14 @@ |
|||||
|
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config') |
||||
|
const { getMetroConfig } = require('@tarojs/rn-supporter') |
||||
|
|
||||
|
/** |
||||
|
* Metro configuration |
||||
|
* https://facebook.github.io/metro/docs/configuration
|
||||
|
* |
||||
|
* @type {import('metro-config').MetroConfig} |
||||
|
*/ |
||||
|
const config = {} |
||||
|
|
||||
|
module.exports = (async function () { |
||||
|
return mergeConfig(getDefaultConfig(__dirname), await getMetroConfig(), config) |
||||
|
})() |
File diff suppressed because it is too large
@ -0,0 +1,214 @@ |
|||||
|
import Taro from '@tarojs/taro'; |
||||
|
import { createOrder, WxPayResult } from '@/api/shop/shopOrder'; |
||||
|
import { OrderCreateRequest } from '@/api/shop/shopOrder/model'; |
||||
|
|
||||
|
/** |
||||
|
* 支付类型枚举 |
||||
|
*/ |
||||
|
export enum PaymentType { |
||||
|
BALANCE = 0, // 余额支付
|
||||
|
WECHAT = 1, // 微信支付
|
||||
|
ALIPAY = 3, // 支付宝支付
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 支付结果回调 |
||||
|
*/ |
||||
|
export interface PaymentCallback { |
||||
|
onSuccess?: () => void; |
||||
|
onError?: (error: string) => void; |
||||
|
onComplete?: () => void; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 统一支付处理类 |
||||
|
*/ |
||||
|
export class PaymentHandler { |
||||
|
|
||||
|
/** |
||||
|
* 执行支付 |
||||
|
* @param orderData 订单数据 |
||||
|
* @param paymentType 支付类型 |
||||
|
* @param callback 回调函数 |
||||
|
*/ |
||||
|
static async pay( |
||||
|
orderData: OrderCreateRequest, |
||||
|
paymentType: PaymentType, |
||||
|
callback?: PaymentCallback |
||||
|
): Promise<void> { |
||||
|
Taro.showLoading({ title: '支付中...' }); |
||||
|
|
||||
|
try { |
||||
|
// 设置支付类型
|
||||
|
orderData.payType = paymentType; |
||||
|
|
||||
|
// 创建订单
|
||||
|
const result = await createOrder(orderData); |
||||
|
|
||||
|
if (!result) { |
||||
|
throw new Error('创建订单失败'); |
||||
|
} |
||||
|
|
||||
|
// 根据支付类型处理
|
||||
|
switch (paymentType) { |
||||
|
case PaymentType.WECHAT: |
||||
|
await this.handleWechatPay(result); |
||||
|
break; |
||||
|
case PaymentType.BALANCE: |
||||
|
await this.handleBalancePay(result); |
||||
|
break; |
||||
|
case PaymentType.ALIPAY: |
||||
|
await this.handleAlipay(result); |
||||
|
break; |
||||
|
default: |
||||
|
throw new Error('不支持的支付方式'); |
||||
|
} |
||||
|
|
||||
|
// 支付成功处理
|
||||
|
Taro.showToast({ |
||||
|
title: '支付成功', |
||||
|
icon: 'success' |
||||
|
}); |
||||
|
|
||||
|
callback?.onSuccess?.(); |
||||
|
|
||||
|
// 跳转到订单页面
|
||||
|
setTimeout(() => { |
||||
|
Taro.switchTab({ url: '/pages/order/order' }); |
||||
|
}, 2000); |
||||
|
|
||||
|
} catch (error: any) { |
||||
|
console.error('支付失败:', error); |
||||
|
const errorMessage = error.message || '支付失败'; |
||||
|
|
||||
|
Taro.showToast({ |
||||
|
title: errorMessage, |
||||
|
icon: 'error' |
||||
|
}); |
||||
|
|
||||
|
callback?.onError?.(errorMessage); |
||||
|
} finally { |
||||
|
Taro.hideLoading(); |
||||
|
callback?.onComplete?.(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理微信支付 |
||||
|
*/ |
||||
|
private static async handleWechatPay(result: WxPayResult): Promise<void> { |
||||
|
if (!result || !result.prepayId) { |
||||
|
throw new Error('微信支付参数错误'); |
||||
|
} |
||||
|
|
||||
|
await Taro.requestPayment({ |
||||
|
timeStamp: result.timeStamp, |
||||
|
nonceStr: result.nonceStr, |
||||
|
package: result.package, |
||||
|
signType: result.signType as any, // 类型转换,因为微信支付的signType是字符串
|
||||
|
paySign: result.paySign, |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理余额支付 |
||||
|
*/ |
||||
|
private static async handleBalancePay(result: any): Promise<void> { |
||||
|
// 余额支付通常在后端直接完成,这里只需要确认结果
|
||||
|
if (!result || !result.orderNo) { |
||||
|
throw new Error('余额支付失败'); |
||||
|
} |
||||
|
// 余额支付成功,无需额外操作
|
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理支付宝支付 |
||||
|
*/ |
||||
|
private static async handleAlipay(_result: any): Promise<void> { |
||||
|
// 支付宝支付逻辑,根据实际情况实现
|
||||
|
throw new Error('支付宝支付暂未实现'); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 快捷支付方法 |
||||
|
*/ |
||||
|
export const quickPay = { |
||||
|
/** |
||||
|
* 微信支付 |
||||
|
*/ |
||||
|
wechat: (orderData: OrderCreateRequest, callback?: PaymentCallback) => { |
||||
|
return PaymentHandler.pay(orderData, PaymentType.WECHAT, callback); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 余额支付 |
||||
|
*/ |
||||
|
balance: (orderData: OrderCreateRequest, callback?: PaymentCallback) => { |
||||
|
return PaymentHandler.pay(orderData, PaymentType.BALANCE, callback); |
||||
|
}, |
||||
|
|
||||
|
/** |
||||
|
* 支付宝支付 |
||||
|
*/ |
||||
|
alipay: (orderData: OrderCreateRequest, callback?: PaymentCallback) => { |
||||
|
return PaymentHandler.pay(orderData, PaymentType.ALIPAY, callback); |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
/** |
||||
|
* 构建单商品订单数据 |
||||
|
*/ |
||||
|
export function buildSingleGoodsOrder( |
||||
|
goodsId: number, |
||||
|
quantity: number = 1, |
||||
|
addressId?: number, |
||||
|
options?: { |
||||
|
comments?: string; |
||||
|
deliveryType?: number; |
||||
|
couponId?: number; |
||||
|
selfTakeMerchantId?: number; |
||||
|
} |
||||
|
): OrderCreateRequest { |
||||
|
return { |
||||
|
goodsItems: [ |
||||
|
{ |
||||
|
goodsId, |
||||
|
quantity |
||||
|
} |
||||
|
], |
||||
|
addressId, |
||||
|
payType: PaymentType.WECHAT, // 默认微信支付,会被PaymentHandler覆盖
|
||||
|
comments: options?.comments || '', |
||||
|
deliveryType: options?.deliveryType || 0, |
||||
|
couponId: options?.couponId, |
||||
|
selfTakeMerchantId: options?.selfTakeMerchantId |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 构建购物车订单数据 |
||||
|
*/ |
||||
|
export function buildCartOrder( |
||||
|
cartItems: Array<{ goodsId: number; quantity: number }>, |
||||
|
addressId?: number, |
||||
|
options?: { |
||||
|
comments?: string; |
||||
|
deliveryType?: number; |
||||
|
couponId?: number; |
||||
|
selfTakeMerchantId?: number; |
||||
|
} |
||||
|
): OrderCreateRequest { |
||||
|
return { |
||||
|
goodsItems: cartItems.map(item => ({ |
||||
|
goodsId: item.goodsId, |
||||
|
quantity: item.quantity |
||||
|
})), |
||||
|
addressId, |
||||
|
payType: PaymentType.WECHAT, // 默认微信支付,会被PaymentHandler覆盖
|
||||
|
comments: options?.comments || '购物车下单', |
||||
|
deliveryType: options?.deliveryType || 0, |
||||
|
couponId: options?.couponId, |
||||
|
selfTakeMerchantId: options?.selfTakeMerchantId |
||||
|
}; |
||||
|
} |
Loading…
Reference in new issue