import React, { useState, useEffect, useCallback, useRef } from 'react' import { View, Text, ScrollView } from '@tarojs/components' import Taro from '@tarojs/taro' import { pageShopOrder, updateShopOrder } from '@/api/shop/shopOrder' import type { ShopOrder, ShopOrderParam } from '@/api/shop/shopOrder/model' import { useUser } from '@/hooks/useUser' import { OrderListStatus, OrderListTabText, OrderStatus } from '@/types/order' import OrderCard from '@/components/common/OrderCard' import EmptyState from '@/components/common/EmptyState' import LoadMore from '@/components/common/LoadMore' import { requireLogin } from '@/utils/login-guard' definePageConfig({ navigationBarTitleText: '我的订单', }) // Tab 配置(使用后端 statusFilter 字段) const tabList = [ { title: OrderListTabText[OrderListStatus.All], status: OrderListStatus.All }, { title: OrderListTabText[OrderListStatus.Unpaid], status: OrderListStatus.Unpaid }, { title: OrderListTabText[OrderListStatus.Unshipped], status: OrderListStatus.Unshipped }, { title: OrderListTabText[OrderListStatus.Shipped], status: OrderListStatus.Shipped }, { title: OrderListTabText[OrderListStatus.Completed], status: OrderListStatus.Completed }, ] interface TabState { orders: ShopOrder[] page: number finished: boolean loading: boolean initialized: boolean } const OrderListPage: React.FC = () => { const { user, isLoggedIn } = useUser() const initTab = Taro.getCurrentInstance().router?.params?.tab ?? Taro.getStorageSync('order_tab') // 读取后清除,避免影响下次进入 if (Taro.getStorageSync('order_tab') !== '') { Taro.removeStorageSync('order_tab') } const [tabIndex, setTabIndex] = useState(Number(initTab) || 0) // 每个 tab 独立维护状态 const [tabStates, setTabStates] = useState( tabList.map(() => ({ orders: [], page: 1, finished: false, loading: false, initialized: false, })) ) const currentState = tabStates[tabIndex] // 用 ref 避免 loadOrders 闭包中捕获过期状态 const tabStatesRef = useRef(tabStates) tabStatesRef.current = tabStates // userId 也用 ref,防止闭包过期导致登录后仍传 undefined const userIdRef = useRef(user?.userId) userIdRef.current = user?.userId const updateTabState = useCallback( (index: number, partial: Partial) => { setTabStates(prev => { const next = [...prev] next[index] = { ...next[index], ...partial } return next }) }, [] ) const loadOrders = useCallback( async (targetIndex: number, p: number) => { // 没有当前登录用户 userId,禁止加载(防止看到别人的订单) const userId = userIdRef.current if (!userId) return const state = tabStatesRef.current[targetIndex] if (state.loading) return updateTabState(targetIndex, { loading: true }) try { const params: ShopOrderParam = { page: p, limit: 10, userId } const status = tabList[targetIndex]?.status // 使用后端 statusFilter 字段进行筛选 // -1=全部, 0=待支付, 1=待发货, 3=待收货, 5=已完成 if (status !== undefined && status !== OrderListStatus.All) { params.statusFilter = status } const res = await pageShopOrder(params) const list = res?.list || [] updateTabState(targetIndex, { orders: p === 1 ? list : [...state.orders, ...list], page: p, finished: list.length < 10, loading: false, initialized: true, }) } catch { updateTabState(targetIndex, { loading: false, initialized: true }) } }, [updateTabState] ) // 切换 tab 时加载数据 useEffect(() => { if (!isLoggedIn) { requireLogin({ action: 'viewOrder', redirect: '/pages/order/list', content: '登录后才能查看订单,是否前往登录?' }) return } // 已登录但 userId 还没拿到,等下次渲染再加载 if (!user?.userId) return if (!tabStates[tabIndex].initialized) { loadOrders(tabIndex, 1) } }, [tabIndex, isLoggedIn, user?.userId]) // 页面每次显示时刷新数据(tabBar 页 switchTab 不会重新挂载组件) const isFirstShow = useRef(true) Taro.useDidShow(() => { // 首次显示由 useEffect 处理,跳过 if (isFirstShow.current) { isFirstShow.current = false return } const userId = userIdRef.current if (!userId) return // 标记所有 tab 为未初始化,切换时会重新加载 setTabStates(prev => prev.map(s => ({ ...s, initialized: false }))) // 立即刷新当前 tab loadOrders(tabIndex, 1) }) const handleLoadMore = () => { if (!currentState.finished && !currentState.loading) { loadOrders(tabIndex, currentState.page + 1) } } /** 取消订单(未付款/待确认收款状态下允许客户取消) */ const handleCloseOrder = (order: ShopOrder) => { Taro.showModal({ title: '确认取消订单', content: '取消后订单将关闭,是否确认?', confirmColor: '#ee0a24', success: async (res) => { if (res.confirm && order?.orderId) { try { await updateShopOrder({ ...order, orderStatus: OrderStatus.Cancelled }) Taro.showToast({ title: '订单已取消', icon: 'success' }) // 标记所有 tab 为未初始化,切换时会重新加载(确保「全部」等 tab 能看到最新状态) setTabStates(prev => prev.map(s => ({ ...s, initialized: false }))) // 立即刷新当前 tab loadOrders(tabIndex, 1) } catch (err: any) { Taro.showToast({ title: err?.message || '取消失败', icon: 'none' }) } } } }) } const handleTabChange = (index: number) => { if (index !== tabIndex) { setTabIndex(index) } } if (!isLoggedIn) { return null } return ( {/* 自定义 Tabs 标题栏 */} {tabList.map((tab, index) => ( handleTabChange(index)} > {tab.title} {index === tabIndex && ( )} ))} {/* 内容区域 - 每个 tab 独立渲染 */} {tabList.map((tab, idx) => ( {tabStates[idx].orders.length > 0 ? ( tabStates[idx].orders.map(order => ( )) ) : tabStates[idx].initialized && !tabStates[idx].loading ? ( ) : null} ))} ) } export default OrderListPage