VideoMonitorEntry.vue 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. <template>
  2. <div v-if="loading || error || device?.typeCode === '20' || video.state.cleanupError" class="video-entry" data-video-entry>
  3. <p v-if="loading" class="video-entry__hint">正在确认视频能力…</p>
  4. <template v-else-if="device?.typeCode === '20'">
  5. <button type="button" data-video-open :disabled="device.bound !== true || device.capabilities?.live !== true || Boolean(video.state.cleanupError)" @click="video.open(device)">监控</button>
  6. <span v-if="!device.capabilities?.live" class="video-entry__hint">{{ device.unavailableReason || '实时视频能力尚未确认' }}</span>
  7. </template>
  8. <p v-if="error" class="video-entry__hint" role="status">{{ error }} <button type="button" @click="load">重查视频能力</button></p>
  9. <p v-if="video.state.cleanupError" class="video-entry__hint" role="alert">{{ video.state.cleanupError }} <button type="button" @click="video.retryCleanup">重试清理</button></p>
  10. </div>
  11. </template>
  12. <script setup>
  13. import { ref, watch, onBeforeUnmount } from 'vue'
  14. import { useVideoStore } from '../stores/videoStore.js'
  15. const props = defineProps({ deviceCode: { type: String, required: true } })
  16. const video = useVideoStore()
  17. const device = ref(null), loading = ref(false), error = ref('')
  18. let generation = 0
  19. async function load() {
  20. const version = ++generation
  21. device.value = null; error.value = ''; loading.value = Boolean(props.deviceCode)
  22. if (!props.deviceCode) return
  23. try {
  24. const result = await video.loadDevice(props.deviceCode)
  25. if (version === generation) device.value = result
  26. } catch (failure) { if (version === generation) error.value = failure.message || '视频能力暂不可用' }
  27. finally { if (version === generation) loading.value = false }
  28. }
  29. watch(() => props.deviceCode, load, { immediate: true })
  30. onBeforeUnmount(() => { generation += 1 })
  31. </script>
  32. <style scoped>
  33. .video-entry { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; padding: 10px 0 14px; }
  34. .video-entry button { color: #c6f7ff; background: #0b5264; border: 1px solid #39879a; border-radius: 4px; padding: 6px 16px; cursor: pointer; }
  35. .video-entry button:disabled { color: #82949c; background: #243841; border-color: #45616a; cursor: not-allowed; }
  36. .video-entry__hint { margin: 0; color: #a7bdc7; font-size: 0.85em; }
  37. </style>