diff --git a/src/views/venues/CameraAlerts.vue b/src/views/venues/CameraAlerts.vue index 39d4324..7a2a94a 100644 --- a/src/views/venues/CameraAlerts.vue +++ b/src/views/venues/CameraAlerts.vue @@ -8,6 +8,7 @@ const tab = ref('health'); const loading = ref(false); const devices = ref>([]); const filters = ref<{ venue_id?: number; status?: string; keyword: string }>({ keyword: '' }) const healthFilter = ref<'all' | 'normal' | 'abnormal'>('all') const retrying = ref>({}) +const acknowledging = ref>({}) const summary = ref>({}) const recipientText = ref('') const statusLabel = (s?: string) => ({ ONLINE_PUSHING: '推送正常', PUSH_SUSPECT: '疑似停止', PUSH_STALE: '推送停止', NETWORK_DOWN: '网络不可达', LOGIN_FAILED: '登录认证失败', ARM_FAILED: '布防失败', NO_PUSH_YET: '尚未收到推送', SERVICE_UNAVAILABLE: '监测服务不可用', UNKNOWN: '未知', DISABLED: '已停用', RECONNECTING: '重连中' }[String(s || 'UNKNOWN')] || String(s || '未知')) @@ -31,7 +32,7 @@ function openEdit(row: CameraDevice) { editing.value = row; form.value = { ...ro async function save() { try { if (editing.value) await updateCameraDevice(editing.value.id, form.value); else await createCameraDevice(form.value); Message.success('已保存'); formVisible.value = false; await load() } catch (e: any) { Message.error(e?.response?.data?.message || e?.message || '保存失败') } } async function retry(row: CameraDevice) { if (retrying.value[row.id]) return; Modal.confirm({ title: '确认重新连接', content: '请确认摄像头已正常在线或已经重启,再重新链接。', okText: '确认重新连接', cancelText: '关闭', onOk: async () => { retrying.value[row.id] = true; try { await retryCameraDevice(row.id); Message.success('重试指令已下发,正在等待登录、布防和客流推送验证'); await new Promise((resolve) => setTimeout(resolve, 5000)); await load(); retrying.value[row.id] = false } catch (e: any) { retrying.value[row.id] = false; Message.error(e?.response?.data?.message || e?.message || '重试失败') } } }) } async function remove(row: CameraDevice) { Modal.confirm({ title: '停用摄像头', content: `确定停用 ${row.name}(${row.ip})吗?`, okText: '确认停用', cancelText: '关闭', onOk: async () => { await deleteCameraDevice(row.id); Message.success('已停用'); await load() } }) } -async function ack(row: CameraAlert) { await acknowledgeCameraAlert(row.id); Message.success('已确认'); await load() } +async function ack(row: CameraAlert) { if (acknowledging.value[row.id]) return; acknowledging.value[row.id] = true; try { await acknowledgeCameraAlert(row.id); Message.success('已确认'); await load() } catch (e: any) { const status = e?.response?.status; Message.error(status === 429 ? '操作过于频繁,请稍后再试' : e?.response?.data?.message || e?.message || '确认处理失败') } finally { acknowledging.value[row.id] = false } } async function saveSettings() { if (!settings.value) return; settings.value.recipient_emails = recipientText.value.split(',').map(x => x.trim()).filter(Boolean); await updateCameraSettings(settings.value); Message.success('通知设置已保存') } let refreshTimer: ReturnType | undefined onMounted(() => { void Promise.all([load(), loadVenues()]); refreshTimer = setInterval(() => { if (!loading.value && !Object.values(retrying.value).some(Boolean)) void load() }, 60000) }) @@ -46,7 +47,7 @@ onUnmounted(() => { if (refreshTimer) clearInterval(refreshTimer) }) - +
超过这个时间没有收到该摄像头的客流数据,系统会判定为推送异常,并继续进行自动重连判断。单位:秒。
保存设置