diff --git a/src/api/shop/shopGoodsSku/index.ts b/src/api/shop/shopGoodsSku/index.ts index 9830507..211f3c7 100644 --- a/src/api/shop/shopGoodsSku/index.ts +++ b/src/api/shop/shopGoodsSku/index.ts @@ -20,9 +20,7 @@ export async function generateGoodsSku(data: ShopGoodsSpec) { export async function pageShopGoodsSku(params: ShopGoodsSkuParam) { const res = await request.get>>( '/shop/shop-goods-sku/page', - { - params - } + params ); if (res.code === 0) { return res.data; @@ -36,9 +34,7 @@ export async function pageShopGoodsSku(params: ShopGoodsSkuParam) { export async function listShopGoodsSku(params?: ShopGoodsSkuParam) { const res = await request.get>( '/shop/shop-goods-sku', - { - params - } + params ); if (res.code === 0 && res.data) { return res.data; diff --git a/src/api/shop/shopOrder/model/index.ts b/src/api/shop/shopOrder/model/index.ts index d70ccb3..2c58b82 100644 --- a/src/api/shop/shopOrder/model/index.ts +++ b/src/api/shop/shopOrder/model/index.ts @@ -89,7 +89,7 @@ export interface ShopOrder { // 代付支付方式,0余额支付, 1微信支付,102微信Native,2会员卡支付,3支付宝,4现金,5POS机,6VIP月卡,7VIP年卡,8VIP次卡,9IC月卡,10IC年卡,11IC次卡,12免费,13VIP充值卡,14IC充值卡,15积分支付,16VIP季卡,17IC季卡,18代付 friendPayType?: number; // 0未付款,1已付款 - payStatus?: number; + payStatus?: boolean; // 0未使用,1已完成,2已取消,3取消中,4退款申请中,5退款被拒绝,6退款成功,7客户端申请退款 orderStatus?: number; // 发货状态(10未发货 20已发货 30部分发货) diff --git a/src/hooks/useCart.ts b/src/hooks/useCart.ts index 66f9c34..e1f1d7f 100644 --- a/src/hooks/useCart.ts +++ b/src/hooks/useCart.ts @@ -9,6 +9,8 @@ export interface CartItem { image: string; quantity: number; addTime: number; + skuId?: number; + specInfo?: string; } // 购物车Hook @@ -51,9 +53,15 @@ export const useCart = () => { name: string; price: string; image: string; + skuId?: number; + specInfo?: string; }, quantity: number = 1) => { const newItems = [...cartItems]; - const existingItemIndex = newItems.findIndex(item => item.goodsId === goods.goodsId); + // 如果有SKU,需要根据goodsId和skuId来判断是否为同一商品 + const existingItemIndex = newItems.findIndex(item => + item.goodsId === goods.goodsId && + (goods.skuId ? item.skuId === goods.skuId : !item.skuId) + ); if (existingItemIndex >= 0) { // 如果商品已存在,增加数量 @@ -66,7 +74,9 @@ export const useCart = () => { price: goods.price, image: goods.image, quantity, - addTime: Date.now() + addTime: Date.now(), + skuId: goods.skuId, + specInfo: goods.specInfo }; newItems.push(newItem); } @@ -98,7 +108,7 @@ export const useCart = () => { return; } - const newItems = cartItems.map(item => + const newItems = cartItems.map(item => item.goodsId === goodsId ? { ...item, quantity } : item ); setCartItems(newItems); diff --git a/src/pages/order/components/OrderList.tsx b/src/pages/order/components/OrderList.tsx index 762dade..2bba785 100644 --- a/src/pages/order/components/OrderList.tsx +++ b/src/pages/order/components/OrderList.tsx @@ -1,4 +1,4 @@ -import {Avatar, Cell, Space, Tabs, Button, TabPane, Image, Toast} from '@nutui/nutui-react-taro' +import {Avatar, Cell, Space, Tabs, Button, TabPane, Image} from '@nutui/nutui-react-taro' import {useEffect, useState, CSSProperties} from "react"; import Taro from '@tarojs/taro'; import {InfiniteLoading} from '@nutui/nutui-react-taro' @@ -10,12 +10,13 @@ import {ShopOrderGoods} from "@/api/shop/shopOrderGoods/model"; import {copyText} from "@/utils/common"; const InfiniteUlStyle: CSSProperties = { - marginTop: '84px', + marginTop: '44px', height: '82vh', width: '100%', padding: '0', overflowY: 'auto', overflowX: 'hidden', + boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)', } const tabs = [ { @@ -61,12 +62,11 @@ function OrderList(props: OrderListProps) { const [hasMore, setHasMore] = useState(true) const [tapIndex, setTapIndex] = useState('0') - console.log(props.statusBarHeight, 'ppp') - // 获取订单状态文本 const getOrderStatusText = (order: ShopOrder) => { - if (order.payStatus === 0) return '待付款'; - if (order.payStatus === 1 && order.deliveryStatus === 10) return '待发货'; + console.log(order,'order') + if (!order.payStatus) return '待付款'; + if (order.payStatus && order.deliveryStatus === 10) return '待发货'; if (order.deliveryStatus === 20) return '待收货'; if (order.deliveryStatus === 30) return '已收货'; if (order.orderStatus === 1) return '已完成'; @@ -151,12 +151,15 @@ function OrderList(props: OrderListProps) { deliveryStatus: 30, // 已收货 orderStatus: 1 // 已完成 }); - Toast.show('确认收货成功'); + Taro.showToast({ + title: '确认收货成功', + }); reload(true); // 重新加载列表 props.onReload?.(); // 通知父组件刷新 } catch (error) { - console.error('确认收货失败:', error); - Toast.show('确认收货失败'); + Taro.showToast({ + title: '确认收货失败', + }); } }; @@ -167,12 +170,16 @@ function OrderList(props: OrderListProps) { ...order, orderStatus: 2 // 已取消 }); - Toast.show('订单已取消'); + Taro.showToast({ + title: '订单已取消', + }); reload(true); // 重新加载列表 props.onReload?.(); // 通知父组件刷新 } catch (error) { console.error('取消订单失败:', error); - Toast.show('取消订单失败'); + Taro.showToast({ + title: '取消订单失败', + }); } }; @@ -185,8 +192,8 @@ function OrderList(props: OrderListProps) { { setTapIndex(paneKey) @@ -225,9 +232,9 @@ function OrderList(props: OrderListProps) { Taro.navigateTo({url: `/shop/orderDetail/index?orderId=${item.orderId}`})}>
- {e.stopPropagation(); copyText(`${item.orderNo}`)}}>{item.orderNo} - {getOrderStatusText(item)} + {getOrderStatusText(item)}
{dayjs(item.createTime).format('YYYY年MM月DD日 HH:mm:ss')}
@@ -249,7 +256,7 @@ function OrderList(props: OrderListProps) { {goods.spec &&
规格:{goods.spec}
}
数量:{goods.totalNum}
-
¥{goods.price}
+
¥{goods.price}
)) ) : ( @@ -271,11 +278,11 @@ function OrderList(props: OrderListProps) { {/* 操作按钮 */} - {item.payStatus === 0 && ( - <> + {item.payStatus && ( + - + )} {item.deliveryStatus === 20 && ( diff --git a/src/pages/order/order.scss b/src/pages/order/order.scss index 1c8a071..8cc23a8 100644 --- a/src/pages/order/order.scss +++ b/src/pages/order/order.scss @@ -1,4 +1,4 @@ page { - background: linear-gradient(to bottom, #e9fff2, #f9fafb); + background: linear-gradient(to bottom, #f3f3f3, #f9fafb); background-size: 100%; } diff --git a/src/pages/order/order.tsx b/src/pages/order/order.tsx index 81683f8..5a69f59 100644 --- a/src/pages/order/order.tsx +++ b/src/pages/order/order.tsx @@ -2,6 +2,7 @@ import {useState} from "react"; // 添加 useCallback 引入 import Taro, {useDidShow} from '@tarojs/taro' import {NavBar, Space, Empty, Button, ConfigProvider} from '@nutui/nutui-react-taro' import {Search} from '@nutui/icons-react-taro' +import { View } from '@tarojs/components'; import OrderList from "./components/OrderList"; import {ShopOrder} from "@/api/shop/shopOrder/model"; import {pageShopOrder} from "@/api/shop/shopOrder"; @@ -25,19 +26,15 @@ function Order() { setStatusBarHeight(res.statusBarHeight) }, }) - // 设置导航栏背景色(含状态栏) - Taro.setNavigationBarColor({ - backgroundColor: '#ffffff', // 状态栏+导航栏背景色 - frontColor: 'black', // 状态栏文字颜色(仅支持 black/white) - }); reload().then() }); // 新增: 添加滚动事件监听 return ( <> +
diff --git a/src/shop/goodsDetail/index.tsx b/src/shop/goodsDetail/index.tsx index 51b9d84..a4b0e9f 100644 --- a/src/shop/goodsDetail/index.tsx +++ b/src/shop/goodsDetail/index.tsx @@ -5,14 +5,25 @@ import Taro, {useShareAppMessage, useShareTimeline} from "@tarojs/taro"; import {RichText, View} from '@tarojs/components' import {ShopGoods} from "@/api/shop/shopGoods/model"; import {getShopGoods} from "@/api/shop/shopGoods"; +import {listShopGoodsSpec} from "@/api/shop/shopGoodsSpec"; +import {ShopGoodsSpec} from "@/api/shop/shopGoodsSpec/model"; +import {listShopGoodsSku} from "@/api/shop/shopGoodsSku"; +import {ShopGoodsSku} from "@/api/shop/shopGoodsSku/model"; import {Swiper} from '@nutui/nutui-react-taro' import navTo, {wxParse} from "@/utils/common"; +import SpecSelector from "@/components/SpecSelector"; import "./index.scss"; import {useCart} from "@/hooks/useCart"; const GoodsDetail = () => { const [goods, setGoods] = useState(null); const [files, setFiles] = useState([]); + const [specs, setSpecs] = useState([]); + const [skus, setSkus] = useState([]); + const [showSpecSelector, setShowSpecSelector] = useState(false); + const [specAction, setSpecAction] = useState<'cart' | 'buy'>('cart'); + const [selectedSku, setSelectedSku] = useState(null); + const [loading, setLoading] = useState(false); const router = Taro.getCurrentInstance().router; const goodsId = router?.params?.id; @@ -31,6 +42,14 @@ const GoodsDetail = () => { }); } + // 如果有规格,显示规格选择器 + if (specs.length > 0) { + setSpecAction('cart'); + setShowSpecSelector(true); + return; + } + + // 没有规格,直接加入购物车 addToCart({ goodsId: goods.goodsId!, name: goods.name || '', @@ -39,8 +58,61 @@ const GoodsDetail = () => { }); }; + // 处理立即购买 + const handleBuyNow = () => { + if (!goods) return; + + if (!Taro.getStorageSync('UserId')) { + return Taro.showToast({ + title: '请先登录', + icon: 'none', + duration: 2000 + }); + } + + // 如果有规格,显示规格选择器 + if (specs.length > 0) { + setSpecAction('buy'); + setShowSpecSelector(true); + return; + } + + // 没有规格,直接购买 + navTo(`/shop/orderConfirm/index?goodsId=${goods?.goodsId}`, true); + }; + + // 规格选择确认回调 + const handleSpecConfirm = (sku: ShopGoodsSku, quantity: number, action: 'cart' | 'buy') => { + setSelectedSku(sku); + setShowSpecSelector(false); + + if (action === 'cart') { + // 加入购物车 + addToCart({ + goodsId: goods!.goodsId!, + skuId: sku.id, + name: goods!.name || '', + price: sku.price || goods!.price || '0', + image: goods!.image || '', + specInfo: sku.sku, // sku字段包含规格信息 + }, quantity); + } else { + // 立即购买 + const orderData = { + goodsId: goods!.goodsId!, + skuId: sku.id, + quantity, + price: sku.price || goods!.price || '0' + }; + navTo(`/shop/orderConfirm/index?orderData=${encodeURIComponent(JSON.stringify(orderData))}`, true); + } + }; + useEffect(() => { if (goodsId) { + setLoading(true); + + // 加载商品详情 getShopGoods(Number(goodsId)) .then((res) => { // 处理富文本内容,去掉图片间距 @@ -52,10 +124,30 @@ const GoodsDetail = () => { const arr = JSON.parse(res.files); arr.length > 0 && setFiles(arr); } - }) .catch((error) => { console.error("Failed to fetch goods detail:", error); + }) + .finally(() => { + setLoading(false); + }); + + // 加载商品规格 + listShopGoodsSpec({ goodsId: Number(goodsId) } as any) + .then((data) => { + setSpecs(data || []); + }) + .catch((error) => { + console.error("Failed to fetch goods specs:", error); + }); + + // 加载商品SKU + listShopGoodsSku({ goodsId: Number(goodsId) } as any) + .then((data) => { + setSkus(data || []); + }) + .catch((error) => { + console.error("Failed to fetch goods skus:", error); }); } }, [goodsId]); @@ -94,7 +186,7 @@ const GoodsDetail = () => { }; }); - if (!goods) { + if (!goods || loading) { return
加载中...
; } @@ -209,11 +301,23 @@ const GoodsDetail = () => { onClick={() => handleAddToCart()}>加入购物车
navTo(`/shop/orderConfirm/index?goodsId=${goods?.goodsId}`, true)}>立即购买 + onClick={() => handleBuyNow()}>立即购买
+ + {/* 规格选择器 */} + {showSpecSelector && ( + setShowSpecSelector(false)} + /> + )} ); }; diff --git a/src/shop/orderConfirm/index.tsx b/src/shop/orderConfirm/index.tsx index 7953877..b50b83d 100644 --- a/src/shop/orderConfirm/index.tsx +++ b/src/shop/orderConfirm/index.tsx @@ -1,7 +1,7 @@ import {useEffect, useState} from "react"; import {Image, Button, Cell, CellGroup, Input, Space, ActionSheet} from '@nutui/nutui-react-taro' import {Location, ArrowRight} from '@nutui/icons-react-taro' -import Taro from '@tarojs/taro' +import Taro, {useDidShow} from '@tarojs/taro' import {ShopGoods} from "@/api/shop/shopGoods/model"; import {getShopGoods} from "@/api/shop/shopGoods"; import {View} from '@tarojs/components'; @@ -87,6 +87,10 @@ const OrderConfirm = () => { await PaymentHandler.pay(orderData, paymentType); }; + useDidShow(() => { + reload().then() + }) + useEffect(() => { if (goodsId) { getShopGoods(Number(goodsId)).then(res => { diff --git a/src/user/address/add.tsx b/src/user/address/add.tsx index 360a87d..c9d2a47 100644 --- a/src/user/address/add.tsx +++ b/src/user/address/add.tsx @@ -254,7 +254,13 @@ const AddUserAddress = () => { width: '100%' }} > - diff --git a/src/utils/payment.ts b/src/utils/payment.ts index 0a9e632..44a7be8 100644 --- a/src/utils/payment.ts +++ b/src/utils/payment.ts @@ -168,13 +168,17 @@ export function buildSingleGoodsOrder( deliveryType?: number; couponId?: number; selfTakeMerchantId?: number; + skuId?: number; + specInfo?: string; } ): OrderCreateRequest { return { goodsItems: [ { goodsId, - quantity + quantity, + skuId: options?.skuId, + specInfo: options?.specInfo } ], addressId,