Day5 video components
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="编辑设备" width="500px">
|
||||
<el-form :model="f" label-width="80px">
|
||||
<el-form-item label="名称"><el-input v-model="f.deviceName"/></el-form-item>
|
||||
<el-form-item label="种类"><el-select v-model="f.deviceCategory" style="width:100%"><el-option v-for="c in cats" :key="c" :label="c" :value="c"/></el-select></el-form-item>
|
||||
<el-form-item label="分组"><el-select v-model="f.deviceGroup" style="width:100%"><el-option v-for="g in groups" :key="g" :label="g" :value="g"/></el-select></el-form-item>
|
||||
<el-form-item label="位置"><el-input v-model="f.location"/></el-form-item>
|
||||
<el-form-item label="启用"><el-switch v-model="f.enable" active-value="启用" inactive-value="禁用"/></el-form-item>
|
||||
<el-form-item label="备注"><el-input v-model="f.remark" type="textarea"/></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button type="primary" @click="save">保存</el-button><el-button @click="visible=false">取消</el-button></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, computed, watch } from 'vue'
|
||||
const props = defineProps({ modelValue: Boolean, device: Object })
|
||||
const emit = defineEmits(['update:modelValue','saved'])
|
||||
const visible = computed({get:()=>props.modelValue,set:v=>emit('update:modelValue',v)})
|
||||
const cats = ['摄像机','硬盘录像机','空调控制器','温湿度变送器','除湿/恒湿机','烟雾报警器','气体报警器','门磁','空调','智能断路器','人行道闸','车辆道闸','485钥匙柜','网络钥匙柜','门禁一体机','红外报警器','紧急报警按钮','动环采集器']
|
||||
const groups = ['视频设备','IoT设备','门禁设备','道闸设备','报警设备']
|
||||
const f = reactive({deviceName:'',deviceCategory:'',deviceGroup:'',location:'',enable:'启用',remark:''})
|
||||
watch(()=>props.device, d=>{if(d)Object.assign(f,d)})
|
||||
const save = ()=>{emit('saved');visible.value=false}
|
||||
</script>
|
||||
@@ -0,0 +1,23 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="实时预览" width="960px" @close="stop">
|
||||
<div class="player"><div v-if="!url" class="loading">加载中...</div>
|
||||
<video v-else ref="vref" :src="wsFlv" autoplay muted controls style="width:100%;height:500px"/></div>
|
||||
<template #footer><el-button @click="visible=false">关闭</el-button></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref, computed, watch } from 'vue'
|
||||
const props = defineProps({ modelValue: Boolean, device: Object })
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const visible = computed({get:()=>props.modelValue,set:v=>emit('update:modelValue',v)})
|
||||
const url = ref(null), vref = ref(null)
|
||||
const wsFlv = computed(()=>url.value?.wsFlv||url.value?.httpFlv)
|
||||
const stop = ()=>url.value=null
|
||||
watch(()=>props.device, async d=>{
|
||||
if(d && visible.value){
|
||||
try{ const r = await fetch(`http://localhost:5100/api/gateway/streams/${d.adapterCode}/${d.sourceId}/live`); url.value = await r.json() }
|
||||
catch(e){}
|
||||
}
|
||||
},{immediate:true})
|
||||
</script>
|
||||
<style scoped>.player{min-height:300px;display:flex;align-items:center;justify-content:center;background:#000}.loading{color:#fff}</style>
|
||||
@@ -8,12 +8,14 @@
|
||||
<el-table-column prop="deviceName" label="名称" min-width="150"/>
|
||||
<el-table-column prop="deviceCategory" label="种类" width="120"/>
|
||||
<el-table-column prop="deviceGroup" label="分组" width="100"/>
|
||||
<el-table-column label="状态" width="80">
|
||||
<template #default="{row}"><el-tag :type="row.isOnline==='在线'?'success':'danger'" size="small">{{row.isOnline}}</el-tag></template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="80"><template #default="{row}"><el-tag :type="row.isOnline==='在线'?'success':'danger'" size="small">{{row.isOnline}}</el-tag></template></el-table-column>
|
||||
<el-table-column prop="adapterCode" label="来源" width="120"/>
|
||||
<el-table-column label="操作" width="120" fixed="right">
|
||||
<template #default="{row}"><el-button size="small" text @click="$emit('edit',row)">编辑</el-button></template>
|
||||
<el-table-column label="操作" width="300" fixed="right">
|
||||
<template #default="{row}">
|
||||
<VideoDeviceActions v-if="row.deviceGroup==='视频设备'" @preview="$emit('preview',row)" @ptz="$emit('ptz',row)" @playback="$emit('playback',row)" @snapshot="$emit('snapshot',row)"/>
|
||||
<el-button v-else size="small" text @click="$emit('edit',row)">编辑</el-button>
|
||||
<el-button size="small" text @click="$emit('map',row)">地图</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
@@ -21,8 +23,9 @@
|
||||
<script setup>
|
||||
import { ref, watch } from 'vue'
|
||||
import { getDevicesByPoint } from '../api/deviceManager'
|
||||
import VideoDeviceActions from './VideoDeviceActions.vue'
|
||||
const props = defineProps({ selectedPoint: Object })
|
||||
defineEmits(['edit'])
|
||||
defineEmits(['edit','map','preview','ptz','playback','snapshot'])
|
||||
const devices = ref([]), loading = ref(false)
|
||||
const loadDevices = async () => {
|
||||
if (!props.selectedPoint?.id) return
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="地图绑定" width="500px">
|
||||
<el-form :model="f" label-width="80px">
|
||||
<el-form-item label="模型ID"><el-input v-model="f.mapModelId"/></el-form-item>
|
||||
<el-form-item label="模型缩放"><el-input-number v-model="f.mapModelScale" :min="0.1" :max="10" :step="0.1"/></el-form-item>
|
||||
<el-form-item label="旋转"><el-input v-model="f.mapModelRotation" placeholder='{"x":0,"y":90,"z":0}'/></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button @click="save" type="primary">保存</el-button><el-button @click="visible=false">取消</el-button></template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { reactive, computed, watch } from 'vue'
|
||||
const props = defineProps({ modelValue: Boolean, device: Object })
|
||||
const emit = defineEmits(['update:modelValue','saved'])
|
||||
const visible = computed({get:()=>props.modelValue,set:v=>emit('update:modelValue',v)})
|
||||
const f = reactive({mapModelId:'',mapModelScale:1,mapModelRotation:''})
|
||||
watch(()=>props.device, d=>{if(d){f.mapModelId=d.mapModelId||'';f.mapModelScale=d.mapModelScale||1;f.mapModelRotation=d.mapModelRotation||''}})
|
||||
const save = ()=>{emit('saved');visible.value=false}
|
||||
</script>
|
||||
@@ -0,0 +1,22 @@
|
||||
<template>
|
||||
<el-dialog v-model="visible" title="云台控制" width="320px">
|
||||
<div class="ptz-pad">
|
||||
<el-button circle @mousedown="go('up')" @mouseup="stop" @mouseleave="stop"><el-icon><ArrowUp/></el-icon></el-button>
|
||||
<div class="ptz-row">
|
||||
<el-button circle @mousedown="go('left')" @mouseup="stop"><el-icon><ArrowLeft/></el-icon></el-button>
|
||||
<el-button circle type="danger" @click="go('stop')"><el-icon><Close/></el-icon></el-button>
|
||||
<el-button circle @mousedown="go('right')" @mouseup="stop"><el-icon><ArrowRight/></el-icon></el-button>
|
||||
</div>
|
||||
<el-button circle @mousedown="go('down')" @mouseup="stop"><el-icon><ArrowDown/></el-icon></el-button>
|
||||
<div class="ptz-row" style="margin-top:8px"><el-button circle @mousedown="go('zoom_in')" @mouseup="stop">+</el-button><el-button circle @mousedown="go('zoom_out')" @mouseup="stop">-</el-button></div>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
const props = defineProps({ modelValue: Boolean, device: Object })
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const visible = computed({get:()=>props.modelValue,set:v=>emit('update:modelValue',v)})
|
||||
const go = async d=>{try{await fetch(`http://localhost:5100/api/gateway/streams/${props.device?.adapterCode}/${props.device?.sourceId}/ptz`,{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({direction:d,speed:.5})})}catch(e){}};const stop = ()=>go('stop')
|
||||
</script>
|
||||
<style scoped>.ptz-pad{display:flex;flex-direction:column;align-items:center;gap:4px}.ptz-row{display:flex;gap:8px}</style>
|
||||
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div class="video-actions">
|
||||
<el-button size="small" type="primary" @click="$emit('preview')"><el-icon><VideoPlay/></el-icon>预览</el-button>
|
||||
<el-button size="small" @click="$emit('ptz')"><el-icon><Aim/></el-icon>云台</el-button>
|
||||
<el-button size="small" @click="$emit('playback')"><el-icon><VideoCamera/></el-icon>回放</el-button>
|
||||
<el-button size="small" @click="$emit('snapshot')"><el-icon><Camera/></el-icon>快照</el-button>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>defineEmits(['preview','ptz','playback','snapshot'])</script>
|
||||
<style scoped>.video-actions{display:flex;gap:4px;flex-wrap:wrap}</style>
|
||||
@@ -1,15 +1,26 @@
|
||||
<template>
|
||||
<div class="device-manager-page">
|
||||
<div class="left-panel"><RegionTree @select-point="onSelect"/></div>
|
||||
<div class="right-panel"><DeviceTable ref="tableRef" :selectedPoint="selectedPoint" @edit="d=>console.log('edit',d)"/></div>
|
||||
<div class="right-panel"><DeviceTable ref="tableRef" :selectedPoint="selectedPoint" @edit="open('edit')" @map="open('map')" @preview="open('preview')" @ptz="open('ptz')" @playback="console.log('playback')" @snapshot="console.log('snapshot')"/></div>
|
||||
<DeviceLivePreview v-model="dlgs.preview" :device="currentDevice"/>
|
||||
<PtzControlPanel v-model="dlgs.ptz" :device="currentDevice"/>
|
||||
<MapBindingPanel v-model="dlgs.map" :device="currentDevice" @saved="refresh"/>
|
||||
<DeviceEditDialog v-model="dlgs.edit" :device="currentDevice" @saved="refresh"/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { ref, reactive } from 'vue'
|
||||
import RegionTree from './components/RegionTree.vue'
|
||||
import DeviceTable from './components/DeviceTable.vue'
|
||||
const selectedPoint = ref(null), tableRef = ref(null)
|
||||
const onSelect = (p) => selectedPoint.value = p
|
||||
import DeviceLivePreview from './components/DeviceLivePreview.vue'
|
||||
import PtzControlPanel from './components/PtzControlPanel.vue'
|
||||
import MapBindingPanel from './components/MapBindingPanel.vue'
|
||||
import DeviceEditDialog from './components/DeviceEditDialog.vue'
|
||||
const selectedPoint = ref(null), tableRef = ref(null), currentDevice = ref(null)
|
||||
const dlgs = reactive({ preview:false, ptz:false, map:false, edit:false })
|
||||
const onSelect = p => selectedPoint.value = p
|
||||
const open = (k) => (d) => { currentDevice.value = d; dlgs[k] = true }
|
||||
const refresh = () => tableRef.value?.loadDevices()
|
||||
</script>
|
||||
<style scoped>
|
||||
.device-manager-page{display:flex;height:calc(100vh-80px)}
|
||||
|
||||
Reference in New Issue
Block a user