This commit is contained in:
liu
2026-08-14 20:21:50 +08:00
parent 4a5b7003ca
commit 03434feb35
21 changed files with 1513 additions and 629 deletions
+205
View File
@@ -0,0 +1,205 @@
import { useCallback, useEffect, useState } from 'react'
import { useRouter } from '@tarojs/taro'
import { View, Text, ScrollView } from '@tarojs/components'
import { Empty, Popup } from '@antmjs/vantui'
import { getBillDetailApi } from '@/services/bill'
import { getOrderDetailApi } from '@/services/order'
import { ORDER_STATUS_TEXT } from '@/types/order'
import type { OrderDetail } from '@/types/order'
import type { BillDetail } from '@/services/bill'
import './index.less'
/**
* 账单详情
* 账单信息 + 金额构成(商品/配送费/筐托盘附加)+ 合并商品明细 + 关联订单(可下钻订单明细)
*/
export default function BillDetailPage() {
const router = useRouter()
const id = Number(router.params.id ?? 0)
const [detail, setDetail] = useState<BillDetail | null>(null)
const [loading, setLoading] = useState(false)
/** 关联订单明细弹层 */
const [showOrder, setShowOrder] = useState(false)
const [orderDetail, setOrderDetail] = useState<OrderDetail | null>(null)
useEffect(() => {
if (!id) return
setLoading(true)
getBillDetailApi(id)
.then(res => setDetail(res.data))
.catch(() => {})
.finally(() => setLoading(false))
}, [id])
/** 下钻关联订单明细 */
const handleOrderTap = useCallback(async (orderId: number) => {
try {
const res = await getOrderDetailApi(orderId)
setOrderDetail(res.data)
setShowOrder(true)
} catch {
// 错误已由 request 层 toast
}
}, [])
if (loading && !detail) {
return <View className='bill-detail'><Empty description='加载中...' /></View>
}
if (!detail) {
return <View className='bill-detail'><Empty description='账单不存在' /></View>
}
const { bill, items, orders } = detail
return (
<View className='bill-detail'>
{/* ===== 账单信息 ===== */}
<View className='bill-card'>
<View className='bill-card__header'>
<Text className='bill-card__no'>{bill.bill_no}</Text>
<Text className={`bill-card__status bill-card__status--${bill.pay_state}`}>
{bill.pay_state_name}
</Text>
</View>
{bill.pay_state === 1 && (
<Text className='bill-card__tip'></Text>
)}
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.bill_date}</Text>
</View>
{bill.purchase && (
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>
{bill.purchase.purchase_no}{bill.purchase.purchase_date}
</Text>
</View>
)}
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.settlement_date}</Text>
</View>
{bill.pay_state === 2 && bill.paid_at && (
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.paid_at}</Text>
</View>
)}
{bill.pay_remark && (
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.pay_remark}</Text>
</View>
)}
{bill.remark && (
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.remark}</Text>
</View>
)}
</View>
{/* ===== 金额构成 ===== */}
<View className='bill-card'>
<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>
</View>
<View className='bill-card__row'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__value'>{bill.delivery_fee}</Text>
</View>
<View className='bill-card__row'>
<Text className='bill-card__label'>
{bill.box_num}×{bill.box_price} {bill.tray_num}×{bill.tray_price}
</Text>
<Text className='bill-card__value'>{bill.added_amount}</Text>
</View>
<View className='bill-card__row bill-card__row--total'>
<Text className='bill-card__label'></Text>
<Text className='bill-card__total'>{bill.total_amount}</Text>
</View>
</View>
{/* ===== 商品明细(跨订单按商品合并) ===== */}
<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'>
<View className='bill-goods__main'>
<Text className='bill-goods__name'>{item.product_name}</Text>
<Text className='bill-goods__spec'>
{item.product_spec ? `${item.product_spec} ` : ''}{item.price}/{item.unit}
</Text>
</View>
<View className='bill-goods__side'>
<Text className='bill-goods__qty'>×{item.quantity}</Text>
<Text className='bill-goods__amount'>{item.amount}</Text>
</View>
</View>
))}
{(items ?? []).length === 0 && <Empty description='暂无商品记录' />}
</View>
{/* ===== 关联订单 ===== */}
<View className='bill-card'>
<Text className='bill-section__title'>{orders?.length ?? 0}</Text>
{(orders ?? []).map(order => (
<View key={order.id} className='bill-order' onClick={() => handleOrderTap(order.id)}>
<View className='bill-order__main'>
<Text className='bill-order__no'>{order.order_no}</Text>
<Text className='bill-order__date'>{order.order_date}</Text>
</View>
<Text className='bill-order__status'>{ORDER_STATUS_TEXT[order.status] || ''}</Text>
<Text className='bill-order__amount'>{order.total_amount}</Text>
</View>
))}
{(orders ?? []).length === 0 && <Empty description='暂无订单记录' />}
</View>
{/* ===== 订单明细弹层 ===== */}
<Popup
show={showOrder}
position='bottom'
round
closeable
closeOnClickOverlay
safeAreaInsetBottom
onClose={() => setShowOrder(false)}
>
{orderDetail && (
<View className='order-popup'>
<Text className='order-popup__title'>{orderDetail.order_no}</Text>
<View className='order-popup__meta'>
<Text>{orderDetail.order_date}</Text>
<Text className='order-popup__status'>
{ORDER_STATUS_TEXT[orderDetail.status] || ''}
</Text>
</View>
<ScrollView scrollY className='order-popup__list'>
{(orderDetail.items ?? []).map(item => (
<View key={item.id} className='order-popup__item'>
<View className='order-popup__item-info'>
<Text className='order-popup__item-name'>{item.product_name}</Text>
<Text className='order-popup__item-spec'>
{item.product_spec ? `${item.product_spec} ` : ''}{item.price}/{item.unit} × {item.quantity}
</Text>
</View>
<Text className='order-popup__item-amount'>{item.amount}</Text>
</View>
))}
</ScrollView>
<View className='order-popup__footer'>
<Text className='order-popup__total'> {orderDetail.total_amount}</Text>
</View>
</View>
)}
</Popup>
</View>
)
}