为了简化API接口,我们将原来的两个计算接口合并为一个统一的 /api/order/calculate
接口,通过 type
参数区分计算模式。
POST /api/order/calculate
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
type | string | 是 | 计算类型:cart (购物车模式)或 goods (商品规格模式) |
address_id | int | 是 | 收货地址ID |
user_coupon_id | int | 否 | 优惠券ID |
cart_ids | array | 条件必填 | 购物车ID列表(当 type=cart 时必填) |
goods_list | array | 条件必填 | 商品列表(当 type=goods 时必填) |
前端请求:
// 立即购买场景:用户在商品详情页选择规格后点击"立即购买"
const calculateByGoods = async (goodsId, skuId, nums, addressId) => {
const response = await fetch('/api/order/calculate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'goods', // 商品规格模式
goods_list: [
{
goods_id: goodsId,
goods_sku_id: skuId,
nums: nums
}
],
address_id: addressId,
user_coupon_id: 0 // 暂不使用优惠券
})
});
const result = await response.json();
console.log('订单预览信息:', result.data);
return result.data;
};
// 调用示例
calculateByGoods(1, 5, 2, 10);
后端响应:
{
"code": 1,
"msg": "获取成功",
"data": {
"coupons": [],
"goods_list": [
{
"goods_id": 1,
"goods_sku_id": 5,
"nums": 2,
"goods": {
"id": 1,
"title": "测试商品",
"image": "/uploads/goods/1.jpg",
"price": "99.00"
},
"sku": {
"id": 5,
"price": "99.00"
},
"sku_attr": "颜色:红色,尺寸:XL"
}
],
"order_info": {
"goodsprice": "198.00",
"shippingfee": "10.00",
"discount": "0.00",
"amount": "208.00",
"saleamount": "208.00"
},
"couponTotalPrice": 198.00
}
}
前端请求:
// 购物车结算场景:用户在购物车页面选择商品后点击"去结算"
const calculateByCart = async (cartIds, addressId, couponId) => {
const response = await fetch('/api/order/calculate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'cart', // 购物车模式
cart_ids: cartIds,
address_id: addressId,
user_coupon_id: couponId || 0
})
});
const result = await response.json();
console.log('订单预览信息:', result.data);
return result.data;
};
// 调用示例
calculateByCart([1, 2, 3], 10, 5);
后端响应:
{
"code": 1,
"msg": "获取成功",
"data": {
"coupons": [
{
"id": 5,
"title": "满200减20",
"condition": 200,
"money": 20
}
],
"goods_list": [
{
"goods_id": 1,
"nums": 2,
"goods": {
"title": "商品A",
"price": "99.00"
}
},
{
"goods_id": 2,
"nums": 1,
"goods": {
"title": "商品B",
"price": "150.00"
}
}
],
"order_info": {
"goodsprice": "348.00",
"shippingfee": "15.00",
"discount": "20.00",
"amount": "363.00",
"saleamount": "343.00"
},
"couponTotalPrice": 348.00
}
}
前端请求:
// 批量购买场景:用户选择多个商品进行批量购买
const calculateBatch = async (goodsList, addressId) => {
const response = await fetch('/api/order/calculate', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'goods', // 商品规格模式
goods_list: goodsList, // 多个商品
address_id: addressId,
user_coupon_id: 0
})
});
return await response.json();
};
// 调用示例:购买3个不同商品
const batchGoods = [
{ goods_id: 1, goods_sku_id: 5, nums: 2 }, // 商品A,红色XL,2件
{ goods_id: 2, goods_sku_id: 0, nums: 1 }, // 商品B,单规格,1件
{ goods_id: 3, goods_sku_id: 8, nums: 3 } // 商品C,蓝色L,3件
];
calculateBatch(batchGoods, 10);
{
"code": 0,
"msg": "计算类型只能是cart或goods",
"data": null
}
{
"code": 0,
"msg": "商品已下架",
"data": null
}
{
"code": 0,
"msg": "商品库存不足,请重新修改数量",
"data": null
}
{
"code": 0,
"msg": "购物车ID列表不能为空",
"data": null
}
<template>
<div class="order-calculate">
<button @click="calculateOrder">计算订单</button>
<div v-if="orderInfo">
<p>商品金额:¥{{ orderInfo.goodsprice }}</p>
<p>运费:¥{{ orderInfo.shippingfee }}</p>
<p>优惠:-¥{{ orderInfo.discount }}</p>
<p>应付:¥{{ orderInfo.saleamount }}</p>
</div>
</div>
</template>
<script>
export default {
data() {
return {
orderInfo: null,
goodsList: [
{ goods_id: 1, goods_sku_id: 5, nums: 2 }
],
cartIds: [1, 2, 3],
addressId: 10,
calculateType: 'goods' // 或 'cart'
}
},
methods: {
async calculateOrder() {
try {
const params = {
type: this.calculateType,
address_id: this.addressId,
user_coupon_id: 0
};
if (this.calculateType === 'goods') {
params.goods_list = this.goodsList;
} else {
params.cart_ids = this.cartIds;
}
const response = await this.$http.post('/api/order/calculate', params);
if (response.data.code === 1) {
this.orderInfo = response.data.data.order_info;
} else {
this.$message.error(response.data.msg);
}
} catch (error) {
console.error('计算订单失败:', error);
this.$message.error('计算订单失败');
}
}
}
}
</script>
import { useState, useCallback } from 'react';
const useOrderCalculate = () => {
const [orderInfo, setOrderInfo] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const calculate = useCallback(async (type, data) => {
setLoading(true);
setError(null);
try {
const params = {
type,
address_id: data.addressId,
user_coupon_id: data.couponId || 0
};
if (type === 'goods') {
params.goods_list = data.goodsList;
} else {
params.cart_ids = data.cartIds;
}
const response = await fetch('/api/order/calculate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params)
});
const result = await response.json();
if (result.code === 1) {
setOrderInfo(result.data.order_info);
} else {
setError(result.msg);
}
} catch (err) {
setError('计算订单失败');
} finally {
setLoading(false);
}
}, []);
return { orderInfo, loading, error, calculate };
};
// 使用示例
const OrderPage = () => {
const { orderInfo, loading, error, calculate } = useOrderCalculate();
const handleCalculate = () => {
calculate('goods', {
goodsList: [{ goods_id: 1, goods_sku_id: 5, nums: 2 }],
addressId: 10,
couponId: 0
});
};
return (
<div>
<button onClick={handleCalculate} disabled={loading}>
{loading ? '计算中...' : '计算订单'}
</button>
{error && <div className="error">{error}</div>}
{orderInfo && (
<div className="order-info">
<p>商品金额:¥{orderInfo.goodsprice}</p>
<p>运费:¥{orderInfo.shippingfee}</p>
<p>优惠:-¥{orderInfo.discount}</p>
<p>应付:¥{orderInfo.saleamount}</p>
</div>
)}
</div>
);
};
type
参数明确区分计算模式type
值这种设计使得前端开发更加简洁,同时保持了功能的完整性和扩展性。