新增打手端新订单语音播报开关
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { SoundOutlined } from '@ant-design/icons'
|
||||
import { Switch, Typography } from 'antd'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
|
||||
import {
|
||||
isWorkerSpeechEnabled,
|
||||
setWorkerSpeechEnabled,
|
||||
speakWorkerText,
|
||||
} from '@/utils/worker-speech'
|
||||
|
||||
/**
|
||||
* 打手端新订单语音播报:开关持久化到 localStorage(默认关闭),
|
||||
* 通过对比抢单大厅缓存中新出现的工单 ID 触发浏览器语音播报。
|
||||
*/
|
||||
export default function WorkerNewOrderSpeech() {
|
||||
const queryClient = useQueryClient()
|
||||
const [enabled, setEnabled] = useState(isWorkerSpeechEnabled)
|
||||
const enabledRef = useRef(enabled)
|
||||
|
||||
useEffect(() => {
|
||||
enabledRef.current = enabled
|
||||
}, [enabled])
|
||||
|
||||
function toggle(checked: boolean) {
|
||||
setEnabled(checked)
|
||||
setWorkerSpeechEnabled(checked)
|
||||
if (checked) speakWorkerText('新订单播报已开启')
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled) return
|
||||
// 首次观察到的大厅快照全部视为已知订单,避免打开开关时播报存量订单。
|
||||
let seenIds: Set<number> | null = null
|
||||
let flushTimer: ReturnType<typeof setTimeout> | null = null
|
||||
const readHallIds = () => {
|
||||
const ids = new Set<number>()
|
||||
for (const [, data] of queryClient.getQueriesData({ queryKey: ['worker-hall-orders'] })) {
|
||||
const pages = (data as { pages?: unknown } | undefined)?.pages
|
||||
if (!Array.isArray(pages)) continue
|
||||
for (const page of pages) {
|
||||
const items = (page as { data?: { items?: unknown } } | null)?.data?.items
|
||||
if (!Array.isArray(items)) continue
|
||||
for (const item of items) {
|
||||
const id = Number((item as { workOrderId?: unknown } | null)?.workOrderId || 0)
|
||||
if (id > 0) ids.add(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids
|
||||
}
|
||||
const unsubscribe = queryClient.getQueryCache().subscribe(() => {
|
||||
if (!enabledRef.current) return
|
||||
const ids = readHallIds()
|
||||
if (!seenIds) {
|
||||
seenIds = ids
|
||||
return
|
||||
}
|
||||
let hasNew = false
|
||||
for (const id of ids) {
|
||||
if (!seenIds.has(id)) hasNew = true
|
||||
}
|
||||
seenIds = ids
|
||||
// 大厅刷新事件可能连发,聚合 2 秒内的多批新订单只播报一次。
|
||||
if (!hasNew || flushTimer) return
|
||||
flushTimer = setTimeout(() => {
|
||||
flushTimer = null
|
||||
speakWorkerText('您有新的订单,请及时抢单')
|
||||
}, 2000)
|
||||
})
|
||||
return () => {
|
||||
if (flushTimer) clearTimeout(flushTimer)
|
||||
unsubscribe()
|
||||
}
|
||||
}, [enabled, queryClient])
|
||||
|
||||
return (
|
||||
<div className="worker-speech-toggle">
|
||||
<SoundOutlined />
|
||||
<Typography.Text>新订单播报</Typography.Text>
|
||||
<Switch size="small" checked={enabled} onChange={toggle} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user