feat(store): 新增门店新订单提醒功能
- 新增 useNewOrderDetector Hook,实现30秒轮询检测新订单 - 订单管理页集成该 Hook,新增订单时震动+Toast提醒 - “全部”Tab 显示新订单红点,切换Tab清空未读计数 - 门店中心页增加待处理订单角标,统一待审核和待处理显示逻辑 - 底部新增“接收新订单提醒”订阅消息授权入口,调用微信接口申请授权 - 文档中补充订阅消息模板ID及字段说明,待后端配合公众号推送消息
This commit is contained in:
@@ -26,3 +26,5 @@ export { useCoupon } from './useCoupon'
|
||||
export { usePagination } from './usePagination'
|
||||
export { usePayment } from './usePayment'
|
||||
export { useScrollHeight } from './useScrollHeight'
|
||||
export { useNewOrderDetector } from './useNewOrderDetector'
|
||||
export type { NewOrderItem, UseNewOrderDetectorOptions, UseNewOrderDetectorReturn } from './useNewOrderDetector'
|
||||
|
||||
129
src/hooks/useNewOrderDetector.ts
Normal file
129
src/hooks/useNewOrderDetector.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
import { useRef, useState, useCallback } from 'react'
|
||||
import { useDidShow, useDidHide } from '@tarojs/taro'
|
||||
|
||||
export interface NewOrderItem {
|
||||
orderId?: number
|
||||
orderNo?: string
|
||||
[key: string]: unknown
|
||||
}
|
||||
|
||||
export interface UseNewOrderDetectorOptions {
|
||||
/** 轮询间隔(毫秒),默认 30000(30秒) */
|
||||
interval?: number
|
||||
/** 获取最新订单列表(按时间降序),返回前几条用于对比 */
|
||||
fetchLatestOrders: () => Promise<NewOrderItem[]>
|
||||
/** 发现新订单时的回调 */
|
||||
onNewOrders?: (count: number, newOrders: NewOrderItem[]) => void
|
||||
}
|
||||
|
||||
export interface UseNewOrderDetectorReturn {
|
||||
/** 未读新订单数 */
|
||||
newOrderCount: number
|
||||
/** 新订单列表 */
|
||||
newOrders: NewOrderItem[]
|
||||
/** 清除未读计数(用户查看后调用) */
|
||||
clearUnread: () => void
|
||||
/** 手动触发一次检测 */
|
||||
checkNow: () => Promise<void>
|
||||
}
|
||||
|
||||
/**
|
||||
* 新订单轮询检测 Hook
|
||||
*
|
||||
* 用于门店订单管理页面,轮询检测是否有新订单产生。
|
||||
* 页面显示时自动启动轮询,隐藏时暂停,避免无效请求。
|
||||
*
|
||||
* @example
|
||||
* const { newOrderCount, newOrders, clearUnread } = useNewOrderDetector({
|
||||
* fetchLatestOrders: () => pageShopOrder({ page: 1, limit: 5 }),
|
||||
* onNewOrders: (count) => Taro.vibrateShort({ type: 'medium' }),
|
||||
* })
|
||||
*/
|
||||
export function useNewOrderDetector(
|
||||
options: UseNewOrderDetectorOptions,
|
||||
): UseNewOrderDetectorReturn {
|
||||
const { interval = 30000, fetchLatestOrders, onNewOrders } = options
|
||||
|
||||
// 已见过的所有 orderId 集合(初始化时需要先加载一次建立基准)
|
||||
const knownOrderIdsRef = useRef<Set<number> | null>(null)
|
||||
// 轮询定时器
|
||||
const timerRef = useRef<ReturnType<typeof setInterval> | null>(null)
|
||||
// 是否正在检测中(防止并发)
|
||||
const detectingRef = useRef(false)
|
||||
|
||||
const [newOrderCount, setNewOrderCount] = useState(0)
|
||||
const [newOrders, setNewOrders] = useState<NewOrderItem[]>([])
|
||||
|
||||
/** 执行一次检测 */
|
||||
const doCheck = useCallback(async () => {
|
||||
if (detectingRef.current) return
|
||||
detectingRef.current = true
|
||||
|
||||
try {
|
||||
const list = await fetchLatestOrders()
|
||||
if (!list || list.length === 0) return
|
||||
|
||||
// 首次加载:建立基准线,不触发提醒
|
||||
if (knownOrderIdsRef.current === null) {
|
||||
knownOrderIdsRef.current = new Set(
|
||||
list.map(o => o.orderId).filter(Boolean) as number[],
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// 对比检测新订单
|
||||
const freshOrders: NewOrderItem[] = []
|
||||
const newIds: number[] = []
|
||||
|
||||
for (const order of list) {
|
||||
const id = order.orderId
|
||||
if (id != null && !knownOrderIdsRef.current.has(id)) {
|
||||
freshOrders.push(order)
|
||||
newIds.push(id)
|
||||
knownOrderIdsRef.current.add(id)
|
||||
}
|
||||
}
|
||||
|
||||
if (freshOrders.length > 0) {
|
||||
setNewOrderCount(prev => prev + freshOrders.length)
|
||||
setNewOrders(prev => [...freshOrders, ...prev])
|
||||
onNewOrders?.(freshOrders.length, freshOrders)
|
||||
}
|
||||
} catch {
|
||||
// 静默失败,不影响页面正常使用
|
||||
} finally {
|
||||
detectingRef.current = false
|
||||
}
|
||||
}, [fetchLatestOrders, onNewOrders])
|
||||
|
||||
/** 清除未读 */
|
||||
const clearUnread = useCallback(() => {
|
||||
setNewOrderCount(0)
|
||||
setNewOrders([])
|
||||
}, [])
|
||||
|
||||
/** 手动触发检测 */
|
||||
const checkNow = useCallback(async () => {
|
||||
await doCheck()
|
||||
}, [doCheck])
|
||||
|
||||
// 页面显示时:初始化基准线 + 启动轮询
|
||||
useDidShow(() => {
|
||||
// 首次加载建立基准(不触发提醒)
|
||||
doCheck()
|
||||
|
||||
// 启动定时轮询
|
||||
if (timerRef.current) clearInterval(timerRef.current)
|
||||
timerRef.current = setInterval(doCheck, interval)
|
||||
})
|
||||
|
||||
// 页面隐藏时:停止轮询
|
||||
useDidHide(() => {
|
||||
if (timerRef.current) {
|
||||
clearInterval(timerRef.current)
|
||||
timerRef.current = null
|
||||
}
|
||||
})
|
||||
|
||||
return { newOrderCount, newOrders, clearUnread, checkNow }
|
||||
}
|
||||
Reference in New Issue
Block a user