商品浏览页构建前最后一次更新
This commit is contained in:
+169
-111
@@ -1,35 +1,48 @@
|
||||
import { View, Text, Image } from '@tarojs/components'
|
||||
import { View, Text, Image, Button } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import { useState, useEffect } from 'react'
|
||||
import './index.scss'
|
||||
import { getOrderList, getDesignList } from '../../utils/store'
|
||||
import ThemeToggle from '../../components/ThemeToggle'
|
||||
import { useThemeContext } from '../../context/ThemeContext'
|
||||
import { getOrderList, getDefaultAddress, getAddressList, type AddressItem, type OrderItem } from '../../utils/store'
|
||||
import { PRODUCT_ICON_MAP } from '../../utils/productConfig'
|
||||
|
||||
export default function OrderDetailPage() {
|
||||
const { theme } = useThemeContext()
|
||||
const [order, setOrder] = useState<any>(null)
|
||||
const [design, setDesign] = useState<any>(null)
|
||||
const params = Taro.getCurrentInstance().router?.params
|
||||
const orderId = params?.orderId || ''
|
||||
|
||||
const [order, setOrder] = useState<OrderItem | null>(null)
|
||||
const [address, setAddress] = useState<AddressItem | null>(null)
|
||||
const [showAddrPicker, setShowAddrPicker] = useState(false)
|
||||
const [addrList, setAddrList] = useState<AddressItem[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
const params = Taro.getCurrentInstance().router?.params
|
||||
const orderId = params?.orderId
|
||||
if (!orderId) return
|
||||
const orders = getOrderList()
|
||||
const found = orders.find(o => o.id === orderId)
|
||||
setOrder(found || null)
|
||||
if (found) {
|
||||
const designs = getDesignList()
|
||||
const related = designs.find(d => d.orderId === orderId)
|
||||
setDesign(related || null)
|
||||
const o = orders.find(x => x.id === orderId)
|
||||
if (o) {
|
||||
setOrder(o)
|
||||
// 优先显示订单已有地址,否则用默认地址
|
||||
if ((o as any).address) {
|
||||
setAddress((o as any).address)
|
||||
} else {
|
||||
setAddress(getDefaultAddress())
|
||||
}
|
||||
}
|
||||
}, [])
|
||||
setAddrList(getAddressList())
|
||||
}, [orderId])
|
||||
|
||||
const STATUS_MAP: Record<string, { label: string; badge: string; desc: string }> = {
|
||||
pending: { label: '待付款', badge: 'badge-pink', desc: '您尚未付款,请及时支付' },
|
||||
paid: { label: '待发货', badge: 'badge-blue', desc: '商家正在准备发货' },
|
||||
shipping: { label: '待收货', badge: 'badge-blue', desc: '快递运输中' },
|
||||
done: { label: '已完成', badge: 'badge-green', desc: '交易已完成' }
|
||||
const handlePickAddress = (addr: AddressItem) => {
|
||||
setAddress(addr)
|
||||
setShowAddrPicker(false)
|
||||
// 同步更新订单里的地址
|
||||
const orders = getOrderList()
|
||||
const idx = orders.findIndex(x => x.id === orderId)
|
||||
if (idx >= 0) {
|
||||
orders[idx] = { ...orders[idx], address: addr } as any
|
||||
// 这里不直接写回 store,用临时状态即可,实际后端会有 order update API
|
||||
}
|
||||
Taro.showToast({ title: '地址已更改', icon: 'success' })
|
||||
}
|
||||
|
||||
if (!order) {
|
||||
@@ -37,15 +50,13 @@ export default function OrderDetailPage() {
|
||||
<View className={`theme-${theme}`}>
|
||||
<View className='order-detail-page'>
|
||||
<View className='page-header dashed-card mt-20'>
|
||||
<Text className='page-title'>订单未找到</Text>
|
||||
<Text className='page-title'>订单不存在</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const status = STATUS_MAP[order.statusCode] || STATUS_MAP.pending
|
||||
|
||||
return (
|
||||
<View className={`theme-${theme}`}>
|
||||
<View className='order-detail-page'>
|
||||
@@ -54,70 +65,79 @@ export default function OrderDetailPage() {
|
||||
<View className='page-header dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='flex-between' style={{ width: '100%' }}>
|
||||
<Text className='back-btn' onClick={() => Taro.navigateBack()}>←</Text>
|
||||
<Text className='back-btn' onTap={() => Taro.navigateBack()}>←</Text>
|
||||
<Text className='page-title'>订单详情</Text>
|
||||
<View style={{ width: '60px' }} />
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 状态卡片 */}
|
||||
<View className='status-card dashed-card mt-20'>
|
||||
{/* 状态横幅 */}
|
||||
<View className='status-banner dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='status-top'>
|
||||
<Text className={`badge ${status.badge} status-badge`}>{status.label}</Text>
|
||||
<Text className='status-desc'>{status.desc}</Text>
|
||||
</View>
|
||||
<View className='logistics-timeline'>
|
||||
<View className='timeline-item active'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-title'>已支付</Text>
|
||||
<Text className='timeline-time'>{order.date}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className='timeline-item'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-title'>商家发货</Text>
|
||||
<Text className='timeline-time'>待更新</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className='timeline-item'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-title'>运输中</Text>
|
||||
<Text className='timeline-time'>待更新</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className='timeline-item'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-title'>已签收</Text>
|
||||
<Text className='timeline-time'>待更新</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Text className='status-text'>
|
||||
{order.statusCode === 'pending' && '待付款'}
|
||||
{order.statusCode === 'paid' && '待发货'}
|
||||
{order.statusCode === 'shipping' && '待收货'}
|
||||
{order.statusCode === 'done' && '已完成'}
|
||||
</Text>
|
||||
<Text className='status-desc'>
|
||||
{order.statusCode === 'pending' && '请在30分钟内完成支付'}
|
||||
{order.statusCode === 'paid' && '商品正在打包中,即将发货'}
|
||||
{order.statusCode === 'shipping' && '快递运输中,请注意查收'}
|
||||
{order.statusCode === 'done' && '交易已完成,感谢惠顾'}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* 地址信息 */}
|
||||
<View className='address-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='address-header'>
|
||||
<Text className='address-icon'>📍</Text>
|
||||
<Text className='address-title'>收货地址</Text>
|
||||
{/* 物流信息(仅 shipping/done) */}
|
||||
{(order.statusCode === 'shipping' || order.statusCode === 'done') && (
|
||||
<View className='logistics-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='logistics-header'>
|
||||
<View className='flex-center'>
|
||||
<Image className='card-icon-img' src='/icon/包裹.png' mode='aspectFit' />
|
||||
<Text className='logistics-title'>物流信息</Text>
|
||||
</View>
|
||||
<Text className='logistics-num'>单号: SF1234567890</Text>
|
||||
</View>
|
||||
<View className='timeline'>
|
||||
<View className='timeline-item active'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-status'>运输中</Text>
|
||||
<Text className='timeline-time'>2024-01-15 14:30</Text>
|
||||
<Text className='timeline-desc'>【北京市】快件已到达北京朝阳转运中心</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className='timeline-item'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-status'>已发货</Text>
|
||||
<Text className='timeline-time'>2024-01-15 09:00</Text>
|
||||
<Text className='timeline-desc'>【深圳市】商家已发货,等待揽收</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View className='timeline-item'>
|
||||
<View className='timeline-dot' />
|
||||
<View className='timeline-content'>
|
||||
<Text className='timeline-status'>已下单</Text>
|
||||
<Text className='timeline-time'>2024-01-14 20:15</Text>
|
||||
<Text className='timeline-desc'>订单已生成,等待商家发货</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<Text className='address-name'>收货人:智绘微刻用户</Text>
|
||||
<Text className='address-phone'>138****8888</Text>
|
||||
<Text className='address-detail'>广东省深圳市南山区科技园智绘微刻总部</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
{/* 商品信息 */}
|
||||
<View className='product-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<Text className='section-title'>商品信息</Text>
|
||||
<View className='product-row'>
|
||||
<View className='product-icon-wrapper'>
|
||||
<Text className='product-icon'>{order.productIcon}</Text>
|
||||
<Image
|
||||
className='product-icon-img'
|
||||
src={order.productIcon?.startsWith('/icon/') ? order.productIcon : '/icon/四角星.png'}
|
||||
mode='aspectFit'
|
||||
/>
|
||||
</View>
|
||||
<View className='product-info'>
|
||||
<Text className='product-name'>{order.productName}</Text>
|
||||
@@ -125,59 +145,97 @@ export default function OrderDetailPage() {
|
||||
</View>
|
||||
</View>
|
||||
<View className='price-row'>
|
||||
<Text className='price-label'>商品总价</Text>
|
||||
<Text className='price-label'>实付款</Text>
|
||||
<Text className='price-value'>{order.price}</Text>
|
||||
</View>
|
||||
<View className='price-row'>
|
||||
<Text className='price-label'>运费</Text>
|
||||
<Text className='price-value'>¥0.00</Text>
|
||||
</View>
|
||||
<View className='price-row total'>
|
||||
<Text className='price-label total-label'>实付款</Text>
|
||||
<Text className='price-value total-value'>{order.price}</Text>
|
||||
</View>
|
||||
|
||||
{/* 收货地址 */}
|
||||
<View className='address-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<View className='address-header'>
|
||||
<View className='flex-center'>
|
||||
<Image className='card-icon-img' src='/icon/地址.png' mode='aspectFit' />
|
||||
<Text className='address-title'>收货地址</Text>
|
||||
</View>
|
||||
<View className='address-change' onTap={() => setShowAddrPicker(true)}>
|
||||
<Text className='change-text'>更改收货地址</Text>
|
||||
</View>
|
||||
</View>
|
||||
{address ? (
|
||||
<View className='address-body'>
|
||||
<View className='address-row'>
|
||||
<Text className='address-name'>{address.name}</Text>
|
||||
<Text className='address-phone'>{address.phone}</Text>
|
||||
</View>
|
||||
<Text className='address-detail'>
|
||||
{address.region?.join(' ')} {address.detail}
|
||||
</Text>
|
||||
</View>
|
||||
) : (
|
||||
<View className='address-empty'>
|
||||
<Text>暂无收货地址,请先添加</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* 订单信息 */}
|
||||
<View className='info-card dashed-card mt-20'>
|
||||
<View className='meta-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<Text className='section-title'>订单信息</Text>
|
||||
<View className='info-row'>
|
||||
<Text className='info-label'>订单编号</Text>
|
||||
<Text className='info-value'>{order.id}</Text>
|
||||
<Text className='meta-title'>订单信息</Text>
|
||||
<View className='meta-row'>
|
||||
<Text className='meta-label'>订单编号</Text>
|
||||
<Text className='meta-value'>{order.id}</Text>
|
||||
</View>
|
||||
<View className='info-row'>
|
||||
<Text className='info-label'>创建时间</Text>
|
||||
<Text className='info-value'>{order.date}</Text>
|
||||
<View className='meta-row'>
|
||||
<Text className='meta-label'>创建时间</Text>
|
||||
<Text className='meta-value'>{order.date}</Text>
|
||||
</View>
|
||||
<View className='info-row'>
|
||||
<Text className='info-label'>支付方式</Text>
|
||||
<Text className='info-value'>微信支付</Text>
|
||||
<View className='meta-row'>
|
||||
<Text className='meta-label'>数量</Text>
|
||||
<Text className='meta-value'>{order.count} 件</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 设计效果 */}
|
||||
{design?.designData?.stickers ? (
|
||||
<View className='preview-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<Text className='section-title'>设计效果</Text>
|
||||
<View className='design-preview' style={{ width: design.designData.category?.mask?.width || 300, height: design.designData.category?.mask?.height || 420 }}>
|
||||
{design.designData.stickers.map((s: any) => (
|
||||
<Image key={s.id} className='preview-sticker' src={s.src} style={{ transform: `translate(${s.x}px, ${s.y}px) scale(${s.scale || 1})`, width: s.width || 200, height: s.height || 200 }} mode='aspectFit' />
|
||||
))}
|
||||
</View>
|
||||
</View>
|
||||
) : design?.designData?.imageSrc ? (
|
||||
<View className='preview-card dashed-card mt-20'>
|
||||
<View className='star-badge' />
|
||||
<Text className='section-title'>设计效果</Text>
|
||||
<View className='design-preview' style={{ width: design.designData.category?.mask?.width || 300, height: design.designData.category?.mask?.height || 420 }}>
|
||||
<Image className='preview-sticker' src={design.designData.imageSrc} style={{ transform: `translate(${design.designData.imagePos?.x || 0}px, ${design.designData.imagePos?.y || 0}px) scale(${design.designData.imagePos?.scale || 1})` }} mode='aspectFit' />
|
||||
</View>
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
<View style={{ height: '40px' }} />
|
||||
|
||||
{/* 地址选择底部弹窗 */}
|
||||
{showAddrPicker && (
|
||||
<View className='modal-overlay' style={{ alignItems: 'flex-end', justifyContent: 'flex-end' }}>
|
||||
<View className='addr-picker-sheet dashed-card'>
|
||||
<View className='addr-picker-header'>
|
||||
<Text className='addr-picker-title'>选择收货地址</Text>
|
||||
<Text className='addr-picker-close' onTap={() => setShowAddrPicker(false)}>✕</Text>
|
||||
</View>
|
||||
<View className='addr-picker-list'>
|
||||
{addrList.map((addr) => (
|
||||
<View
|
||||
key={addr.id}
|
||||
className={`addr-picker-item ${address?.id === addr.id ? 'active' : ''}`}
|
||||
onTap={() => handlePickAddress(addr)}
|
||||
>
|
||||
<View className='addr-picker-row'>
|
||||
<Text className='addr-picker-name'>{addr.name}</Text>
|
||||
<Text className='addr-picker-phone'>{addr.phone}</Text>
|
||||
{addr.isDefault && <Text className='addr-picker-default'>默认</Text>}
|
||||
</View>
|
||||
<Text className='addr-picker-detail'>
|
||||
{addr.region?.join(' ')} {addr.detail}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
{addrList.length === 0 && (
|
||||
<View className='addr-picker-empty'>
|
||||
<Text>暂无地址,请先添加收货地址</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
<View className='addr-picker-add' onTap={() => { setShowAddrPicker(false); Taro.navigateTo({ url: '/pages/address/index' }) }}>
|
||||
<Text className='addr-picker-add-text'>+ 新建收货地址</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user