优化金额显示等
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
// 购物车悬浮球:右下角,底部避让自定义 tabBar(110rpx + 安全区)
|
||||
.cart-ball {
|
||||
position: fixed;
|
||||
right: 24rpx;
|
||||
left: 24rpx;
|
||||
bottom: calc(150rpx + env(safe-area-inset-bottom));
|
||||
z-index: 998;
|
||||
display: flex;
|
||||
|
||||
@@ -15,13 +15,15 @@ interface PriceTextProps {
|
||||
* - block 独占一行(窄卡片:首页推荐、商品列表、购物车)
|
||||
*/
|
||||
mode?: 'inline' | 'block'
|
||||
/** 单位 */
|
||||
price_unit?: string | null
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品价格:售价 + 零售价标注(小字)
|
||||
* price=30、spec=15 → ¥30 零售价:¥2
|
||||
*/
|
||||
export default function PriceText({ price, spec, className, mode = 'inline' }: PriceTextProps) {
|
||||
export default function PriceText({ price, spec, className, mode = 'inline', price_unit }: PriceTextProps) {
|
||||
const retail = formatRetailPrice(price, spec)
|
||||
|
||||
// 窄卡片:大价格 / 零售价上下两行,避免与右侧按钮(+/步进器)挤压换行
|
||||
@@ -30,7 +32,7 @@ export default function PriceText({ price, spec, className, mode = 'inline' }: P
|
||||
<View className={`price-text ${className ?? ''}`}>
|
||||
<Text className='price-text__main'>¥{price}</Text>
|
||||
{retail !== null && (
|
||||
<Text className='price-text__retail'>单价:¥{retail}</Text>
|
||||
<Text className='price-text__retail'>单价:¥{retail} {price_unit}</Text>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
@@ -40,7 +42,7 @@ export default function PriceText({ price, spec, className, mode = 'inline' }: P
|
||||
<Text className={className}>
|
||||
¥{price}
|
||||
{retail !== null && (
|
||||
<Text className='price-text__retail price-text__retail--inline'>单价:¥{retail}</Text>
|
||||
<Text className='price-text__retail price-text__retail--inline'>单价:¥{retail} {price_unit}</Text>
|
||||
)}
|
||||
</Text>
|
||||
)
|
||||
|
||||
@@ -147,12 +147,6 @@
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__qty {
|
||||
font-size: 24rpx;
|
||||
color: #969799;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&__amount {
|
||||
font-size: 28rpx;
|
||||
color: #323233;
|
||||
|
||||
@@ -5,8 +5,7 @@ import { Empty, Popup } from '@antmjs/vantui'
|
||||
import { getBillDetailApi } from '@/services/bill'
|
||||
import { getOrderDetailApi } from '@/services/order'
|
||||
import { ORDER_STATUS_TEXT } from '@/types/order'
|
||||
import { formatSpec, resolveFileUrl } from '@/utils/format'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import {formatRetailPrice, formatSpec, resolveFileUrl} from '@/utils/format'
|
||||
import type { OrderDetail } from '@/types/order'
|
||||
import type { BillDetail } from '@/services/bill'
|
||||
import './index.less'
|
||||
@@ -60,18 +59,9 @@ export default function BillDetailPage() {
|
||||
|
||||
const { bill, items, orders } = detail
|
||||
|
||||
/** 附加金额:正=压筐附加,负=回筐抵扣(0 不带头符号) */
|
||||
const addedNum = Number(bill.added_amount)
|
||||
const addedLabel = addedNum < 0 ? '回筐抵扣' : '压筐附加'
|
||||
const addedText =
|
||||
addedNum < 0
|
||||
? `-¥${Math.abs(addedNum).toFixed(2)}`
|
||||
: addedNum > 0
|
||||
? `+¥${addedNum.toFixed(2)}`
|
||||
: '¥0.00'
|
||||
/** 筐/托盘明细:正压负回,数量取绝对值(单价为出账时快照) */
|
||||
const boxPart = `${bill.box_num < 0 ? '回筐' : '压筐'} ${Math.abs(bill.box_num)}×¥${bill.box_price}`
|
||||
const trayPart = `${bill.tray_num < 0 ? '回托盘' : '压托盘'} ${Math.abs(bill.tray_num)}×¥${bill.tray_price}`
|
||||
const boxTotalPrice = (Number(bill.box_price) * bill.box_num).toFixed(2)
|
||||
const trayTotalPrice = (Number(bill.tray_price) * bill.tray_num).toFixed(2)
|
||||
|
||||
return (
|
||||
<View className={`bill-detail ${bill.can_pay ? 'bill-detail--pay' : ''}`}>
|
||||
@@ -124,7 +114,7 @@ export default function BillDetailPage() {
|
||||
|
||||
{/* ===== 金额构成 ===== */}
|
||||
<View className='bill-card'>
|
||||
<Text className='bill-section__title'>金额构成</Text>
|
||||
<Text className='bill-section__title'>金额明细</Text>
|
||||
<View className='bill-card__row'>
|
||||
<Text className='bill-card__label'>商品金额</Text>
|
||||
<Text className='bill-card__value'>¥{bill.product_amount}</Text>
|
||||
@@ -134,9 +124,21 @@ export default function BillDetailPage() {
|
||||
<Text className='bill-card__value'>¥{bill.delivery_fee}</Text>
|
||||
</View>
|
||||
<View className='bill-card__row'>
|
||||
<Text className='bill-card__label'>{addedLabel}({boxPart},{trayPart})</Text>
|
||||
<Text className={`bill-card__value ${addedNum < 0 ? 'bill-card__value--return' : ''}`}>
|
||||
{addedText}
|
||||
<Text className='bill-card__label'>周转筐({bill.box_price} × {bill.box_num})</Text>
|
||||
<Text className={`bill-card__value ${Number(boxTotalPrice) < 0 ? 'bill-card__value--return' : ''}`}>
|
||||
{Number(boxTotalPrice) < 0 ? `- ¥${boxTotalPrice}` : `¥${boxTotalPrice}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View className='bill-card__row'>
|
||||
<Text className='bill-card__label'>周转托盘({bill.tray_price} × {bill.tray_num})</Text>
|
||||
<Text className={`bill-card__value ${Number(trayTotalPrice) < 0 ? 'bill-card__value--return' : ''}`}>
|
||||
{Number(trayTotalPrice) < 0 ? `- ¥${trayTotalPrice}` : `¥${trayTotalPrice}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View className='bill-card__row'>
|
||||
<Text className='bill-card__label'>售后</Text>
|
||||
<Text className={`bill-card__value ${Number(bill.after_sale) < 0 ? 'bill-card__value--return' : ''}`}>
|
||||
{Number(bill.after_sale) < 0 ? `- ¥${bill.after_sale}` : `¥${bill.after_sale}`}
|
||||
</Text>
|
||||
</View>
|
||||
<View className='bill-card__row bill-card__row--total'>
|
||||
@@ -148,7 +150,6 @@ export default function BillDetailPage() {
|
||||
{/* ===== 商品明细(跨订单按商品合并) ===== */}
|
||||
<View className='bill-card'>
|
||||
<Text className='bill-section__title'>商品明细({items?.length ?? 0})</Text>
|
||||
<Text className='bill-section__desc'>同一商品跨订单合并,单价为加权平均价</Text>
|
||||
{(items ?? []).map(item => (
|
||||
<View key={item.product_id} className='bill-goods'>
|
||||
{!!item.image && (
|
||||
@@ -162,13 +163,11 @@ export default function BillDetailPage() {
|
||||
<View className='bill-goods__main'>
|
||||
<Text className='bill-goods__name'>{item.product_name}</Text>
|
||||
<Text className='bill-goods__spec'>
|
||||
{formatSpec(item.product_spec, item.unit)}{' '}
|
||||
<PriceText price={item.price} spec={item.product_spec} />
|
||||
{formatSpec(item.product_spec, item.unit)}{' ¥'}{item.price}
|
||||
</Text>
|
||||
</View>
|
||||
<View className='bill-goods__side'>
|
||||
<Text className='bill-goods__qty'>×{item.quantity}</Text>
|
||||
<Text className='bill-goods__amount'>¥{item.amount}</Text>
|
||||
<Text className='bill-goods__amount'>¥{item.price} × {item.quantity}</Text>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
@@ -216,11 +215,11 @@ export default function BillDetailPage() {
|
||||
<View className='order-popup__item-info'>
|
||||
<Text className='order-popup__item-name'>{item.product_name}</Text>
|
||||
<Text className='order-popup__item-spec'>
|
||||
{formatSpec(item.product_spec, item.unit)}{' '}
|
||||
<PriceText price={item.price} spec={item.product_spec} /> × {item.quantity}
|
||||
{formatSpec(item.product_spec, item.unit)}{' '}
|
||||
单价:{formatRetailPrice(item.price, item.product_spec)} {item.price_unit}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className='order-popup__item-amount'>¥{item.amount}</Text>
|
||||
<Text className='order-popup__item-amount'>¥{item.price} × {item.quantity}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
|
||||
@@ -88,6 +88,15 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&__spec-tag {
|
||||
margin-left: 12rpx;
|
||||
font-size: 24rpx;
|
||||
color: #969799;
|
||||
border-radius: 6rpx;
|
||||
padding: 2rpx 8rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
&__invalid-tag {
|
||||
margin-left: 12rpx;
|
||||
font-size: 20rpx;
|
||||
@@ -167,6 +176,7 @@
|
||||
padding: 16rpx 24rpx;
|
||||
border-top: 1rpx solid #ebedf0;
|
||||
box-sizing: border-box;
|
||||
z-index: 99;
|
||||
|
||||
&__total {
|
||||
flex: 1;
|
||||
|
||||
+10
-10
@@ -6,8 +6,7 @@ import useAuthStore from '@/stores/auth/useAuthStore'
|
||||
import useCartStore from '@/stores/cart/useCartStore'
|
||||
import { createOrderApi } from '@/services/order'
|
||||
import { getStoreInfoApi } from '@/services/store'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import { formatSpec } from '@/utils/format'
|
||||
import {formatRetailPrice, formatSpec} from '@/utils/format'
|
||||
import type { CartItem } from '@/types/cart'
|
||||
import type { StoreDetail } from '@/types/store'
|
||||
import './index.less'
|
||||
@@ -159,7 +158,7 @@ export default function CartPage() {
|
||||
if (submitting) return
|
||||
setSubmitting(true)
|
||||
try {
|
||||
const res = await createOrderApi({
|
||||
await createOrderApi({
|
||||
items: purchasable.map(item => ({
|
||||
product_id: item.product_id,
|
||||
quantity: Number(qtyMap[item.id] ?? item.quantity),
|
||||
@@ -221,13 +220,12 @@ export default function CartPage() {
|
||||
<Text className='cart-item__name'>{item.name}</Text>
|
||||
{item.status === 0 && <Text className='cart-item__invalid-tag'>已失效</Text>}
|
||||
</View>
|
||||
<Text className='cart-item__spec'>{formatSpec(item.spec, item.unit)}</Text>
|
||||
<Text className='cart-item__spec'>
|
||||
{formatSpec(item.spec, item.unit)}{' '}
|
||||
单价:{formatRetailPrice(item.price, item.spec)} {item.price_unit}
|
||||
</Text>
|
||||
<View className='cart-item__bottom'>
|
||||
{item.price !== null ? (
|
||||
<PriceText className='cart-item__price' price={item.price} spec={item.spec} mode='block' />
|
||||
) : (
|
||||
<Text className='cart-item__price cart-item__price--none'>价格待定</Text>
|
||||
)}
|
||||
<Text className='cart-item__price'>¥{item.price}</Text>
|
||||
{item.status === 1 ? (
|
||||
<Stepper
|
||||
value={displayQty(item)}
|
||||
@@ -252,6 +250,8 @@ export default function CartPage() {
|
||||
))
|
||||
)}
|
||||
|
||||
<View style={{ height: 100 }}></View>
|
||||
|
||||
{loggedIn && hasInvalid && (
|
||||
<View className='cart-invalid-hint'>
|
||||
<Text>部分商品已下架或未设置您所在等级的价格,不可下单</Text>
|
||||
@@ -262,7 +262,7 @@ export default function CartPage() {
|
||||
{loggedIn && items.length > 0 && (
|
||||
<View className='cart-footer'>
|
||||
<View className='cart-footer__total'>
|
||||
<Text className='cart-footer__label'>合计(可购{totalQuantity}件)</Text>
|
||||
<Text className='cart-footer__label'>合计{totalQuantity}件</Text>
|
||||
<Text className='cart-footer__amount'>¥{totalAmount}</Text>
|
||||
</View>
|
||||
<Button type='danger' className='cart-footer__submit' onClick={handleOrderTap}>
|
||||
|
||||
@@ -274,8 +274,8 @@
|
||||
font-size: 28rpx;
|
||||
color: #323233;
|
||||
font-weight: 500;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
margin-right: 20rpx;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -284,7 +284,6 @@
|
||||
margin-top: 8rpx;
|
||||
font-size: 22rpx;
|
||||
color: #969799;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
@@ -2,17 +2,15 @@ import { useCallback, useMemo, useState } from 'react'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import { View, Text, Image } from '@tarojs/components'
|
||||
import { Grid, GridItem, Icon, Search, Swiper, SwiperItem } from '@antmjs/vantui'
|
||||
import useAuthStore from '@/stores/auth/useAuthStore'
|
||||
import useCartStore from '@/stores/cart/useCartStore'
|
||||
import { getHomeConfigApi } from '@/services/home'
|
||||
import type { HomeConfig } from '@/services/home'
|
||||
import { getProductListApi } from '@/services/product'
|
||||
import { getProductCover } from '@/types/product'
|
||||
import type { Product, ProductCartPatch } from '@/types/product'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import CartBall from '@/components/CartBall'
|
||||
import CartStepper from '@/components/CartStepper'
|
||||
import { formatSpec } from '@/utils/format'
|
||||
import {formatRetailPrice, formatSpec} from '@/utils/format'
|
||||
import './index.less'
|
||||
|
||||
/** 首页 → 商品页的本地存储传参 key(switchTab 无法带参) */
|
||||
@@ -265,10 +263,15 @@ export default function IndexPage() {
|
||||
/>
|
||||
<View className='product-card__info'>
|
||||
<Text className='product-card__name'>{product.name}</Text>
|
||||
<Text className='product-card__spec'>{formatSpec(product.spec, product.unit)}</Text>
|
||||
<View className='product-card__spec'>
|
||||
{formatSpec(product.spec, product.unit)}{' '}
|
||||
{product.price !== null && <>
|
||||
单价:{formatRetailPrice(product.price, product.spec)} {product.price_unit}
|
||||
</>}
|
||||
</View>
|
||||
<View className='product-card__bottom'>
|
||||
{product.price !== null ? (
|
||||
<PriceText className='product-card__price' price={product.price} spec={product.spec} mode='block' />
|
||||
<Text className='product-card__price'>¥{product.price}</Text>
|
||||
) : (
|
||||
<Text className='product-card__price product-card__price--none'>登陆后查看价格</Text>
|
||||
)}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Empty, Popup } from '@antmjs/vantui'
|
||||
import useAuthStore from '@/stores/auth/useAuthStore'
|
||||
import { cancelOrderApi, getOrderDetailApi, getOrderListApi } from '@/services/order'
|
||||
import { ORDER_STATUS_FILTERS, ORDER_STATUS_TEXT } from '@/types/order'
|
||||
import { formatSpec, resolveFileUrl } from '@/utils/format'
|
||||
import {formatRetailPrice, formatSpec, resolveFileUrl} from '@/utils/format'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import type { OrderDetail, OrderListItem, OrderStatus } from '@/types/order'
|
||||
import './index.less'
|
||||
@@ -264,10 +264,10 @@ export default function OrderListPage() {
|
||||
<Text className='detail-popup__item-name'>{item.product_name}</Text>
|
||||
<Text className='detail-popup__item-spec'>
|
||||
{formatSpec(item.product_spec, item.unit)}{' '}
|
||||
<PriceText price={item.price} spec={item.product_spec} /> × {item.quantity}
|
||||
单价:{formatRetailPrice(item.price, item.product_spec)} {item.price_unit}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className='detail-popup__item-amount'>¥{item.amount}</Text>
|
||||
<Text className='detail-popup__item-amount'>¥{item.price} × {item.quantity}</Text>
|
||||
</View>
|
||||
))}
|
||||
</ScrollView>
|
||||
|
||||
@@ -32,24 +32,11 @@ const PAY_METHODS: Array<{ value: PayMethod; label: string; icon: string; desc:
|
||||
|
||||
/**
|
||||
* 发起付款页(合并付款)
|
||||
* 选择本店可付款账单(?payable=1)→ 选择支付方式 → 提交:
|
||||
* - 在线支付(仅小程序):wx.login 取 code → 后端经旺铺网关下单 → 调起微信支付 → 主动查询同步结果(回调兜底)
|
||||
* - 线下凭证:展示收款码 / 对公账户 → 上传汇款凭证 → 提交,后台审核
|
||||
* 支持 ?ids=1,2 预选账单(账单详情页"去付款"跳转)
|
||||
*/
|
||||
export default function PaymentPage() {
|
||||
const router = useRouter()
|
||||
const token = useAuthStore(s => s.token)
|
||||
const loggedIn = !!token
|
||||
|
||||
/** 预选账单(路由参数,仅在首次加载时消费一次) */
|
||||
const presetRef = useRef<number[] | null>(
|
||||
(router.params.ids || '')
|
||||
.split(',')
|
||||
.map(Number)
|
||||
.filter(n => n > 0),
|
||||
)
|
||||
|
||||
const [bills, setBills] = useState<Bill[]>([])
|
||||
const [selectedIds, setSelectedIds] = useState<number[]>([])
|
||||
const [page, setPage] = useState(1)
|
||||
@@ -79,11 +66,7 @@ export default function PaymentPage() {
|
||||
setBills(prev => (reset ? data : [...prev, ...data]))
|
||||
setPage(pageNum)
|
||||
setFinished(pageNum * PAGE_SIZE >= total)
|
||||
if (presetRef.current) {
|
||||
const preset = presetRef.current
|
||||
presetRef.current = null
|
||||
setSelectedIds(prev => Array.from(new Set([...prev, ...preset])))
|
||||
}
|
||||
setSelectedIds(prev => Array.from(new Set([...prev, ...data.map(i => i.id)])))
|
||||
} catch {
|
||||
// 错误已由 request 层 toast
|
||||
} finally {
|
||||
|
||||
@@ -5,8 +5,7 @@ import { Empty, Stepper, Swiper, SwiperItem } from '@antmjs/vantui'
|
||||
import useAuthStore from '@/stores/auth/useAuthStore'
|
||||
import useCartStore from '@/stores/cart/useCartStore'
|
||||
import { getProductDetailApi } from '@/services/product'
|
||||
import { formatSpec, resolveFileUrl } from '@/utils/format'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import {formatRetailPrice, formatSpec, resolveFileUrl} from '@/utils/format'
|
||||
import type { Product } from '@/types/product'
|
||||
import './index.less'
|
||||
|
||||
@@ -116,7 +115,7 @@ export default function ProductDetailPage() {
|
||||
<View className='goods-card'>
|
||||
<View className='goods-card__price-row'>
|
||||
{product.price !== null ? (
|
||||
<PriceText className='goods-card__price' price={product.price} spec={product.spec} />
|
||||
<Text className='goods-card__price'>¥{product.price}</Text>
|
||||
) : (
|
||||
<Text className='goods-card__price goods-card__price--none'>
|
||||
{loggedIn ? '价格待定' : '登录后查看价格'}
|
||||
@@ -124,7 +123,12 @@ export default function ProductDetailPage() {
|
||||
)}
|
||||
</View>
|
||||
<Text className='goods-card__name'>{product.name}</Text>
|
||||
<Text className='goods-card__spec'>{formatSpec(product.spec, product.unit)}</Text>
|
||||
<Text className='goods-card__spec'>
|
||||
{formatSpec(product.spec, product.unit)}{' '}
|
||||
{product.price !== null && <>
|
||||
单价:{formatRetailPrice(product.price, product.spec)} {product.price_unit}
|
||||
</>}
|
||||
</Text>
|
||||
<View className='goods-card__meta'>
|
||||
{!!product.shelf_life && product.shelf_life > 0 && (
|
||||
<Text className='goods-card__tag'>保质期 {product.shelf_life} 天</Text>
|
||||
|
||||
+15
-80
@@ -1,16 +1,15 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import { View, Text, Image, ScrollView } from '@tarojs/components'
|
||||
import { Button, Empty, Popup, Search, Stepper } from '@antmjs/vantui'
|
||||
import { Empty, Search } from '@antmjs/vantui'
|
||||
import useCartStore from '@/stores/cart/useCartStore'
|
||||
import { getCategoriesApi, getProductListApi } from '@/services/product'
|
||||
import type { ProductListParams } from '@/services/product'
|
||||
import { getProductCover } from '@/types/product'
|
||||
import type { Category, Product, ProductCartPatch } from '@/types/product'
|
||||
import PriceText from '@/components/PriceText'
|
||||
import CartBall from '@/components/CartBall'
|
||||
import CartStepper from '@/components/CartStepper'
|
||||
import { formatSpec } from '@/utils/format'
|
||||
import {formatRetailPrice, formatSpec} from '@/utils/format'
|
||||
import './index.less'
|
||||
|
||||
const PAGE_SIZE = 10
|
||||
@@ -43,12 +42,6 @@ export default function ProductPage() {
|
||||
/** 是否有请求进行中(仅用于避免"加载更多"并发) */
|
||||
const loadingRef = useRef(false)
|
||||
|
||||
/** 加购弹层 */
|
||||
const [showPopup, setShowPopup] = useState(false)
|
||||
const [current, setCurrent] = useState<Product | null>(null)
|
||||
const [qty, setQty] = useState(1)
|
||||
const addingRef = useRef(false)
|
||||
|
||||
/** 当前选中二级分类所属的一级分类ID(用于父级高亮) */
|
||||
const activeParentId = useMemo(() => {
|
||||
if (activeId == null) return null
|
||||
@@ -191,13 +184,6 @@ export default function ProductPage() {
|
||||
setSearchKey('')
|
||||
}, [])
|
||||
|
||||
/** 打开加购弹层 */
|
||||
const handleAddTap = useCallback((product: Product) => {
|
||||
setCurrent(product)
|
||||
setQty(1)
|
||||
setShowPopup(true)
|
||||
}, [])
|
||||
|
||||
/** 行内加减购确认后回写列表项的购物车字段 */
|
||||
const handleRowSync = useCallback((productId: number, patch: ProductCartPatch) => {
|
||||
setProducts(prev => prev.map(p => (p.id === productId ? { ...p, ...patch } : p)))
|
||||
@@ -209,20 +195,15 @@ export default function ProductPage() {
|
||||
}, [])
|
||||
|
||||
/** 确认加购(用返回的购物车行回写列表项,行内随即展示加减器) */
|
||||
const handleConfirmAdd = useCallback(async () => {
|
||||
if (!current || addingRef.current) return
|
||||
addingRef.current = true
|
||||
const handleConfirmAdd = useCallback(async (product: Product) => {
|
||||
try {
|
||||
const res = await addItem(current.id, qty)
|
||||
handleRowSync(current.id, { cart_id: res.id, cart_quantity: res.quantity })
|
||||
const res = await addItem(product.id, 1)
|
||||
handleRowSync(product.id, { cart_id: res.id, cart_quantity: res.quantity })
|
||||
Taro.showToast({ title: '已加入购物车', icon: 'success' })
|
||||
setShowPopup(false)
|
||||
} catch {
|
||||
// 错误(未设等级价/数量上限)已由 request 层 toast
|
||||
} finally {
|
||||
addingRef.current = false
|
||||
|
||||
}
|
||||
}, [current, qty, addItem, handleRowSync])
|
||||
}, [addItem, handleRowSync])
|
||||
|
||||
return (
|
||||
<View className='product-page'>
|
||||
@@ -307,10 +288,15 @@ export default function ProductPage() {
|
||||
/>
|
||||
<View className='product-item__info'>
|
||||
<Text className='product-item__name'>{product.name}</Text>
|
||||
<Text className='product-item__spec'>{formatSpec(product.spec, product.unit)}</Text>
|
||||
<Text className='product-item__spec'>
|
||||
{formatSpec(product.spec, product.unit)}{' '}
|
||||
{product.price !== null && <>
|
||||
单价:{formatRetailPrice(product.price, product.spec)} {product.price_unit}
|
||||
</>}
|
||||
</Text>
|
||||
<View className='product-item__bottom'>
|
||||
{product.price !== null ? (
|
||||
<PriceText className='product-item__price' price={product.price} spec={product.spec} mode='block' />
|
||||
<Text className='product-item__price'>¥{product.price}</Text>
|
||||
) : (
|
||||
<Text className='product-item__price product-item__price--none'>价格待定</Text>
|
||||
)}
|
||||
@@ -322,7 +308,7 @@ export default function ProductPage() {
|
||||
className='product-item__add'
|
||||
onClick={e => {
|
||||
e.stopPropagation()
|
||||
handleAddTap(product)
|
||||
handleConfirmAdd(product)
|
||||
}}
|
||||
>
|
||||
<Text className='product-item__add-icon'>+</Text>
|
||||
@@ -343,57 +329,6 @@ export default function ProductPage() {
|
||||
</ScrollView>
|
||||
</View>
|
||||
|
||||
{/* ========== 加购弹层 ========== */}
|
||||
<Popup
|
||||
show={showPopup}
|
||||
position='bottom'
|
||||
round
|
||||
closeable
|
||||
closeOnClickOverlay
|
||||
safeAreaInsetBottom
|
||||
style={{ paddingBottom: '110px' }}
|
||||
onClose={() => setShowPopup(false)}
|
||||
>
|
||||
{current && (
|
||||
<View className='add-popup'>
|
||||
<View className='add-popup__product'>
|
||||
<Image
|
||||
className='add-popup__image'
|
||||
src={getProductCover(current) || 'https://img.yzcdn.cn/vant/cat.jpeg'}
|
||||
mode='aspectFill'
|
||||
/>
|
||||
<View className='add-popup__info'>
|
||||
<Text className='add-popup__name'>{current.name}</Text>
|
||||
<Text className='add-popup__spec'>{formatSpec(current.spec, current.unit)}</Text>
|
||||
{current.price !== null ? (
|
||||
<PriceText className='add-popup__price' price={current.price} spec={current.spec} />
|
||||
) : (
|
||||
<Text className='add-popup__price add-popup__price--none'>价格待定</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<View className='add-popup__row'>
|
||||
<Text className='add-popup__label'>购买数量</Text>
|
||||
<Stepper
|
||||
value={qty}
|
||||
min={1}
|
||||
max={99999999.99}
|
||||
onChange={e => setQty(Number(e.detail))}
|
||||
/>
|
||||
</View>
|
||||
<Button
|
||||
type='danger'
|
||||
block
|
||||
round
|
||||
className='add-popup__submit'
|
||||
onClick={handleConfirmAdd}
|
||||
>
|
||||
加入购物车
|
||||
</Button>
|
||||
</View>
|
||||
)}
|
||||
</Popup>
|
||||
|
||||
{/* ========== 购物车悬浮球 ========== */}
|
||||
<CartBall />
|
||||
</View>
|
||||
|
||||
@@ -44,6 +44,8 @@ export interface Bill {
|
||||
settlement_date: string
|
||||
/** 付款时间(已支付时非空) */
|
||||
paid_at: string | null
|
||||
/** 售后金额 */
|
||||
after_sale: string
|
||||
/** 付款备注 */
|
||||
pay_remark: string
|
||||
/** 账单备注 */
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface CartItem {
|
||||
amount: string | null
|
||||
/** 1 可购 / 0 商品下架、缺失或未设等级价 */
|
||||
status: number
|
||||
price_unit: string
|
||||
}
|
||||
|
||||
/** 购物车列表数据 */
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface OrderItem {
|
||||
product_name: string
|
||||
product_spec: string
|
||||
unit: string
|
||||
price_unit: string
|
||||
/** 下单时门店等级实际价快照 */
|
||||
price: string
|
||||
quantity: number
|
||||
|
||||
@@ -27,6 +27,7 @@ export interface Product {
|
||||
content: string
|
||||
/** 当前门店等级的实际销售价(未登录/未绑店/未设等级为 null) */
|
||||
price: string | null
|
||||
price_unit: string | null
|
||||
images_arr: ProductImage[]
|
||||
/** 所属分类(详情接口 with 返回) */
|
||||
category?: { id: number; name: string } | null
|
||||
|
||||
@@ -10,8 +10,8 @@ const LOGIN_PATH = '/pages/login/index'
|
||||
/** 默认请求超时(ms) */
|
||||
const DEFAULT_TIMEOUT = 15000
|
||||
/** 接口根地址(uploadFile 等原生请求同样使用) */
|
||||
// export const BASE_URL = "http://localhost:8000/index.php"
|
||||
export const BASE_URL = "https://purchase.henanklkj.com/index.php"
|
||||
export const BASE_URL = "http://localhost:8000/index.php"
|
||||
// export const BASE_URL = "https://purchase.henanklkj.com/index.php"
|
||||
|
||||
/**
|
||||
* HTTP 状态码 → 错误提示映射
|
||||
|
||||
Reference in New Issue
Block a user