优化下单流程

This commit is contained in:
2025-07-30 02:44:58 +08:00
parent 19fe9b4775
commit 5dd02be44b
12 changed files with 540 additions and 66 deletions

View File

@@ -8,7 +8,7 @@ import {View} from '@tarojs/components';
import {listShopUserAddress} from "@/api/shop/shopUserAddress";
import {ShopUserAddress} from "@/api/shop/shopUserAddress/model";
import './index.scss'
import {useCart} from "@/hooks/useCart";
import {useCart, CartItem} from "@/hooks/useCart";
import Gap from "@/components/Gap";
import {createOrder} from "@/api/shop/shopOrder";
import {OrderCreateRequest} from "@/api/shop/shopOrder/model";
@@ -19,11 +19,13 @@ const OrderConfirm = () => {
const [goods, setGoods] = useState<ShopGoods | null>(null);
const [address, setAddress] = useState<ShopUserAddress>()
const [payment, setPayment] = useState<Payment>()
const [checkoutItems, setCheckoutItems] = useState<CartItem[]>([]);
const router = Taro.getCurrentInstance().router;
const goodsId = router?.params?.goodsId;
const {
cartItems
cartItems,
removeFromCart
} = useCart();
const reload = async () => {
@@ -34,6 +36,25 @@ const OrderConfirm = () => {
}
}
// 加载结算商品数据
const loadCheckoutItems = () => {
try {
const checkoutData = Taro.getStorageSync('checkout_items');
if (checkoutData) {
const items = JSON.parse(checkoutData) as CartItem[];
setCheckoutItems(items);
// 清除临时存储的数据
Taro.removeStorageSync('checkout_items');
} else {
// 如果没有选中商品数据,使用全部购物车商品
setCheckoutItems(cartItems);
}
} catch (error) {
console.error('加载结算商品失败:', error);
setCheckoutItems(cartItems);
}
};
/**
* 统一支付入口
*/
@@ -47,9 +68,9 @@ const OrderConfirm = () => {
return;
}
if (!cartItems || cartItems.length === 0) {
if (!checkoutItems || checkoutItems.length === 0) {
Taro.showToast({
title: '购物车为空',
title: '没有要结算的商品',
icon: 'error'
});
return;
@@ -57,7 +78,7 @@ const OrderConfirm = () => {
// 构建订单数据
const orderData = buildCartOrder(
cartItems.map(item => ({
checkoutItems.map(item => ({
goodsId: item.goodsId!,
quantity: item.quantity || 1
})),
@@ -72,7 +93,14 @@ const OrderConfirm = () => {
const paymentType = payment?.type === 0 ? PaymentType.BALANCE : PaymentType.WECHAT;
// 执行支付
await PaymentHandler.pay(orderData, paymentType);
await PaymentHandler.pay(orderData, paymentType, {
onSuccess: () => {
// 支付成功后,从购物车中移除已下单的商品
checkoutItems.forEach(item => {
removeFromCart(item.goodsId);
});
}
});
};
useEffect(() => {
@@ -83,12 +111,21 @@ const OrderConfirm = () => {
console.error("Failed to fetch goods detail:", error);
});
}
reload().then()
}, [goodsId]);
reload().then();
loadCheckoutItems();
}, [goodsId, cartItems]);
if (!goods) {
return <div>...</div>;
}
// 计算总价
const getTotalPrice = () => {
return checkoutItems.reduce((total, item) => {
return total + (parseFloat(item.price) * item.quantity);
}, 0).toFixed(2);
};
// 计算商品总数量
const getTotalQuantity = () => {
return checkoutItems.reduce((total, item) => total + item.quantity, 0);
};
return (
<div className={'order-confirm-page'}>
@@ -122,7 +159,7 @@ const OrderConfirm = () => {
</CellGroup>
<CellGroup>
{cartItems.map((goods, _) => (
{checkoutItems.map((goods, _) => (
<Cell key={goods.goodsId}>
<Space>
<Image src={goods.image} mode={'aspectFill'} style={{
@@ -143,10 +180,10 @@ const OrderConfirm = () => {
</CellGroup>
<CellGroup>
<Cell title={'商品总价(共3件'} extra={<View className={'font-medium'}>{'¥' + goods.price}</View>}/>
<Cell title={`商品总价(共${getTotalQuantity()}件)`} extra={<View className={'font-medium'}>{'¥' + getTotalPrice()}</View>}/>
<Cell title={'优惠券'} extra={(
<View className={'flex justify-between items-center'}>
<View className={'text-red-500 text-sm mr-1'}>-10.00</View>
<View className={'text-red-500 text-sm mr-1'}>-0.00</View>
<ArrowRight className={'text-gray-400'} size={14}/>
</View>
)}/>
@@ -164,7 +201,7 @@ const OrderConfirm = () => {
<View className={'btn-bar flex justify-between items-center'}>
<div className={'flex justify-center items-center mx-4'}>
<span className={'total-price text-sm text-gray-500'}></span>
<span className={'text-red-500 text-xl font-bold'}>{goods.price}</span>
<span className={'text-red-500 text-xl font-bold'}>{getTotalPrice()}</span>
</div>
<div className={'buy-btn mx-4'}>
<Button type="success" size="large" onClick={onPay}></Button>

View File

@@ -3,20 +3,14 @@ import {Cell, CellGroup, Image, Space, Button} from '@nutui/nutui-react-taro'
import Taro from '@tarojs/taro'
import {ShopOrder} from "@/api/shop/shopOrder/model";
import {getShopOrder} from "@/api/shop/shopOrder";
import {listOrderGoods} from "@/api/system/orderGoods";
import {OrderGoods} from "@/api/system/orderGoods/model";
import {getShopGoods} from "@/api/shop/shopGoods";
import {listShopOrderGoods} from "@/api/shop/shopOrderGoods";
import {ShopOrderGoods} from "@/api/shop/shopOrderGoods/model";
import dayjs from "dayjs";
import './index.scss'
interface OrderGoodsDetail extends OrderGoods {
goodsName?: string;
goodsImage?: string;
}
const OrderDetail = () => {
const [order, setOrder] = useState<ShopOrder | null>(null);
const [orderGoodsList, setOrderGoodsList] = useState<OrderGoodsDetail[]>([]);
const [orderGoodsList, setOrderGoodsList] = useState<ShopOrderGoods[]>([]);
const router = Taro.getCurrentInstance().router;
const orderId = router?.params?.orderId;
@@ -55,19 +49,9 @@ const OrderDetail = () => {
setOrder(res);
// 获取订单商品列表
const goodsRes = await listOrderGoods({ orderId: Number(orderId) });
const goodsRes = await listShopOrderGoods({ orderId: Number(orderId) });
if (goodsRes && goodsRes.length > 0) {
const goodsDetailsPromises = goodsRes.map(async (item) => {
console.log(item,'item.>>>')
const shopGoods = await getShopGoods(Number(item.goodsId));
return {
...item,
goodsName: shopGoods?.name,
goodsImage: shopGoods?.image,
};
});
const detailedGoodsList = await Promise.all(goodsDetailsPromises);
setOrderGoodsList(detailedGoodsList);
setOrderGoodsList(goodsRes);
}
}).catch(error => {
console.error("Failed to fetch order detail:", error);
@@ -91,11 +75,12 @@ const OrderDetail = () => {
{orderGoodsList.map((item, index) => (
<Cell key={index}>
<div className={'flex items-center'}>
<Image src={item.goodsImage} width="80" height="80" lazyLoad={false} />
<Image src={item.image || '/default-goods.png'} width="80" height="80" lazyLoad={false} />
<div className={'ml-2'}>
<div className={'text-sm font-bold'}>{item.goodsName}</div>
{item.spec && <div className={'text-gray-500 text-xs'}>{item.spec}</div>}
<div className={'text-gray-500 text-xs'}>{item.totalNum}</div>
<div className={'text-red-500 text-lg'}>{item.payPrice}</div>
<div className={'text-red-500 text-lg'}>{item.price}</div>
</div>
</div>
</Cell>