Files
wechat_wc/src/pages/orderDetail/index.tsx
T
broccoli b19a56003f 添加登录和后端校验
完成后端设计(未在本仓库体现),通过安全的手段完成了登录鉴权
2026-08-06 16:27:36 +08:00

245 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { View, Text, Image, Button } from '@tarojs/components'
import Taro from '@tarojs/taro'
import { useState, useEffect } from 'react'
import './index.scss'
import { useThemeContext } from '../../context/ThemeContext'
import { useSafeArea } from '../../hooks/useSafeArea'
import { useStatusBar } from '../../hooks/useStatusBar'
import { getOrderList, getDefaultAddress, getAddressList, type AddressItem, type OrderItem } from '../../utils/store'
import { PRODUCT_ICON_MAP } from '../../utils/productConfig'
export default function OrderDetailPage() {
const { theme, resolvedTheme } = useThemeContext()
const safe = useSafeArea()
useStatusBar(resolvedTheme)
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 orders = getOrderList()
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 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) {
return (
<View className={`theme-${resolvedTheme}`}>
<View className='order-detail-page'>
<View className='page-header dashed-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<Text className='page-title'>订单不存在</Text>
</View>
</View>
</View>
)
}
return (
<View className={`theme-${resolvedTheme}`}>
<View className='order-detail-page'>
<View className='page-header dashed-card mt-20' style={{ marginTop: `${safe.headerPaddingTop}px` }}>
<View className='star-badge' />
<View className='flex-between' style={{ width: '100%' }}>
<Text className='back-btn' onTap={() => Taro.navigateBack()}></Text>
<Text className='page-title'>订单详情</Text>
<View style={{ width: '60px' }} />
</View>
</View>
{/* 状态横幅 */}
<View className='status-banner dashed-card mt-20'>
<View className='star-badge' />
<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>
{/* 物流信息(仅 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>
)}
{/* 商品信息 */}
<View className='product-card dashed-card mt-20'>
<View className='star-badge' />
<View className='product-row'>
<View className='product-icon-wrapper'>
<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>
<Text className='product-sku'>{order.sku}</Text>
</View>
</View>
<View className='price-row'>
<Text className='price-label'>实付款</Text>
<Text className='price-value'>{order.price}</Text>
</View>
</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='meta-card dashed-card mt-20'>
<View className='star-badge' />
<Text className='meta-title'>订单信息</Text>
<View className='meta-row'>
<Text className='meta-label'>订单编号</Text>
<Text className='meta-value'>{order.id}</Text>
</View>
<View className='meta-row'>
<Text className='meta-label'>创建时间</Text>
<Text className='meta-value'>{order.date}</Text>
</View>
<View className='meta-row'>
<Text className='meta-label'>数量</Text>
<Text className='meta-value'>{order.count} </Text>
</View>
</View>
<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>
)
}