import { computed, onBeforeUnmount, ref } from 'vue' import { useRoute } from 'vue-router' import { cancelFaultRecordOperation, createFaultRecordOperation, getFaultRecordOperation, } from '@/service/faultRecord' import type { FaultRecordCreateReq, FaultRecordEnv, FaultRecordOpDetail, } from '@/service/faultRecord/interface' import { ENV_LABEL, errText, isTerminal } from './constants' /** 当前页面所属环境(来自路由 meta.env) */ export function useFaultRecordEnv() { const route = useRoute() const env = computed(() => (route.meta.env === 'test' ? 'test' : 'prod')) const envLabel = computed(() => ENV_LABEL[env.value]) return { env, envLabel } } // 轮询间隔:开始后 10 秒内每 2 秒(及时看到设备应答),之后每 5 秒(等待 379/上传/下载,状态变化慢) const POLL_FAST_INTERVAL = 2000 const POLL_FAST_PERIOD = 10_000 const POLL_SLOW_INTERVAL = 5000 /** 创建操作并轮询状态,直到结束 */ export function useOperation(onFinished?: (d: FaultRecordOpDetail) => void) { const detail = ref() const running = ref(false) const error = ref('') let timer: ReturnType | undefined let watchingId = '' // 每次开始轮询递增;只有最新一轮可以继续排下一次,避免请求在途时重复开始导致多条轮询并行 let generation = 0 let startedAt = 0 function stop() { generation++ if (timer) clearTimeout(timer) timer = undefined running.value = false } async function poll(gen: number) { const id = watchingId try { const d = await getFaultRecordOperation(id) if (gen !== generation) return detail.value = d if (isTerminal(d.status)) { stop() onFinished?.(d) return } } catch (e) { if (gen !== generation) return error.value = errText(e) } const interval = Date.now() - startedAt < POLL_FAST_PERIOD ? POLL_FAST_INTERVAL : POLL_SLOW_INTERVAL timer = setTimeout(poll, interval, gen) } /** 查看某个已有操作(如从历史中选择),未结束时继续轮询;对正在轮询的同一操作重复调用不会重新开始 */ function watch(id: string) { if (id === watchingId && running.value) return stop() watchingId = id error.value = '' running.value = true startedAt = Date.now() poll(generation) } async function start(req: FaultRecordCreateReq) { error.value = '' detail.value = undefined const { id } = await createFaultRecordOperation(req) watch(id) return id } async function cancel() { if (!detail.value) return await cancelFaultRecordOperation(detail.value.id) } onBeforeUnmount(stop) return { detail, running, error, start, watch, cancel, stop } }