fix(order): 修复订单列表页登录后仍看到别人订单问题
- 使用 userIdRef 避免闭包过期,确保加载订单时 userId 正确 - loadOrders 函数开头增加硬拦截,没有 userId 则不加载订单 - useEffect 中添加 user?.userId 判断,等待有效 userId 再加载 - useEffect 依赖数组加入 user?.userId,userId 变化时重新加载订单 feat(index): 首页铃铛接入新订单轮询与提示 - 登录后获取店员身份,使用 isClerkRef 避免闭包问题 - 通过 useNewOrderDetector 每30秒轮询门店订单,仅店员有效 - 新订单时触发震动和提示,铃铛数字角标动态显示新订单数 - 铃铛点击区分店员和普通用户,店员跳门店订单页并清除未读 - 页面展示时刷新店员身份,确保身份状态及时更新
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import React, { useState, useEffect, useCallback, useRef } from 'react'
|
||||
import { View, Text, ScrollView, Swiper, SwiperItem, Image } from '@tarojs/components'
|
||||
import Taro from '@tarojs/taro'
|
||||
import Taro, { useDidShow } from '@tarojs/taro'
|
||||
import { useUser } from '@/hooks/useUser'
|
||||
import { useShare } from '@/hooks/useShare'
|
||||
import { useScrollHeight } from '@/hooks/useScrollHeight'
|
||||
import { useNewOrderDetector } from '@/hooks/useNewOrderDetector'
|
||||
import { getMyClerk } from '@/api/shop/shopStoreUser'
|
||||
import { pageShopOrder } from '@/api/shop/shopOrder'
|
||||
import { listCmsAd } from '@/api/cms/cmsAd'
|
||||
import { listCmsArticle } from '@/api/cms/cmsArticle'
|
||||
import { pageShopGoods } from '@/api/shop/shopGoods'
|
||||
@@ -35,6 +38,62 @@ const IndexPage: React.FC = () => {
|
||||
enableCopyUrl: true,
|
||||
})
|
||||
|
||||
// ─── 门店店员身份检测 ──────────────────────────────────────────
|
||||
const [isClerk, setIsClerk] = useState(false)
|
||||
const isClerkRef = useRef(false)
|
||||
|
||||
// 登录后检查是否为门店店员
|
||||
useEffect(() => {
|
||||
if (!isLoggedIn) {
|
||||
setIsClerk(false)
|
||||
isClerkRef.current = false
|
||||
return
|
||||
}
|
||||
getMyClerk()
|
||||
.then(data => {
|
||||
const clerk = !!data
|
||||
setIsClerk(clerk)
|
||||
isClerkRef.current = clerk
|
||||
})
|
||||
.catch(() => {
|
||||
setIsClerk(false)
|
||||
isClerkRef.current = false
|
||||
})
|
||||
}, [isLoggedIn])
|
||||
|
||||
// 页面重新显示时也刷新店员身份(可能从其他页面回来时状态变了)
|
||||
useDidShow(() => {
|
||||
if (isLoggedIn) {
|
||||
getMyClerk()
|
||||
.then(data => {
|
||||
const clerk = !!data
|
||||
setIsClerk(clerk)
|
||||
isClerkRef.current = clerk
|
||||
})
|
||||
.catch(() => {
|
||||
isClerkRef.current = false
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// ─── 新订单轮询检测(仅店员生效)────────────────────────────────
|
||||
const { newOrderCount, clearUnread } = useNewOrderDetector({
|
||||
interval: 30000, // 30 秒轮询一次
|
||||
fetchLatestOrders: useCallback(() => {
|
||||
// 非店员不请求,返回空数组(baseline 不会建立,无副作用)
|
||||
if (!isClerkRef.current) return Promise.resolve([])
|
||||
return pageShopOrder({ page: 1, limit: 5 }).then(r => r?.list || [])
|
||||
}, []),
|
||||
onNewOrders: useCallback((count) => {
|
||||
Taro.vibrateShort({ type: 'medium' })
|
||||
Taro.showToast({
|
||||
title: `您有 ${count} 条新订单`,
|
||||
icon: 'none',
|
||||
duration: 2500,
|
||||
})
|
||||
}, []),
|
||||
})
|
||||
|
||||
|
||||
const categories = ['全部', '球拍', '球鞋', '服装', '配件']
|
||||
|
||||
@@ -94,6 +153,13 @@ const IndexPage: React.FC = () => {
|
||||
Taro.navigateTo({ url: '/passport/login' })
|
||||
return
|
||||
}
|
||||
// 店员 → 跳转门店订单管理页,有新订单时清除未读计数
|
||||
if (isClerk) {
|
||||
if (newOrderCount > 0) clearUnread()
|
||||
Taro.navigateTo({ url: '/pages/store/orders/index' })
|
||||
return
|
||||
}
|
||||
// 普通用户 → 跳消息通知页
|
||||
Taro.navigateTo({ url: '/pages/index/notification' })
|
||||
}
|
||||
|
||||
@@ -121,9 +187,16 @@ const IndexPage: React.FC = () => {
|
||||
<Text className='text-gray-400 text-sm flex-1'>搜索商品</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View onClick={handleMessageClick}>
|
||||
<View onClick={handleMessageClick} className='relative'>
|
||||
<Text className='text-xl'>🔔</Text>
|
||||
{isLoggedIn && (
|
||||
{isLoggedIn && newOrderCount > 0 && (
|
||||
<View className='absolute -top-1 -right-1 min-w-[16px] h-4 px-1 bg-red-500 rounded-full flex items-center justify-center'>
|
||||
<Text className='text-white text-[10px] leading-none font-medium'>
|
||||
{newOrderCount > 99 ? '99+' : newOrderCount}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
{isLoggedIn && newOrderCount === 0 && (
|
||||
<View className='absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full' />
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -58,6 +58,10 @@ const OrderListPage: React.FC = () => {
|
||||
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<TabState>) => {
|
||||
setTabStates(prev => {
|
||||
@@ -71,13 +75,17 @@ const OrderListPage: React.FC = () => {
|
||||
|
||||
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: user?.userId }
|
||||
const params: ShopOrderParam = { page: p, limit: 10, userId }
|
||||
const status = tabList[targetIndex]?.status
|
||||
|
||||
// 使用后端 statusFilter 字段进行筛选
|
||||
@@ -109,10 +117,12 @@ const OrderListPage: React.FC = () => {
|
||||
requireLogin({ action: 'viewOrder', redirect: '/pages/order/list', content: '登录后才能查看订单,是否前往登录?' })
|
||||
return
|
||||
}
|
||||
// 已登录但 userId 还没拿到,等下次渲染再加载
|
||||
if (!user?.userId) return
|
||||
if (!tabStates[tabIndex].initialized) {
|
||||
loadOrders(tabIndex, 1)
|
||||
}
|
||||
}, [tabIndex, isLoggedIn])
|
||||
}, [tabIndex, isLoggedIn, user?.userId])
|
||||
|
||||
const handleLoadMore = () => {
|
||||
if (!currentState.finished && !currentState.loading) {
|
||||
|
||||
Reference in New Issue
Block a user