V4修复: 改用vol-box弹窗+Vue3写法 全部写在base_device.vue中
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
<!--
|
||||
*Author:jxx
|
||||
*Date:{Date}
|
||||
*Contact:283591387@qq.com
|
||||
*业务请在@/extension/warehouse/device_manager/base_device.jsx或base_device.vue文件编写
|
||||
*新版本支持vue或【表.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
|
||||
-->
|
||||
<template>
|
||||
<view-grid ref="grid"
|
||||
@@ -24,98 +20,159 @@
|
||||
:rowClick="rowClick"
|
||||
:modelOpenBefore="modelOpenBefore"
|
||||
:modelOpenAfter="modelOpenAfter">
|
||||
<!-- 自定义组件数据槽扩展,更多数据槽slot见文档 -->
|
||||
<template #gridHeader>
|
||||
</template>
|
||||
</view-grid>
|
||||
|
||||
<!-- 实时预览 -->
|
||||
<vol-box :lazy="true" v-model="previewVisible" title="实时预览" :width="960" :padding="10">
|
||||
<div style="background:#000;min-height:400px;display:flex;align-items:center;justify-content:center">
|
||||
<div v-if="!wsFlv" style="color:#fff">{{ loading ? '加载中...' : '无法获取流地址' }}</div>
|
||||
<video v-else ref="playerRef" :src="wsFlv" autoplay muted controls style="width:100%;height:450px" />
|
||||
</div>
|
||||
<template #footer><el-button size="small" @click="previewVisible=false">关闭</el-button></template>
|
||||
</vol-box>
|
||||
|
||||
<!-- 云台控制 -->
|
||||
<vol-box :lazy="true" v-model="ptzVisible" title="云台控制" :width="320" :padding="10">
|
||||
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
|
||||
<el-button circle @mousedown="ptzGo('up')" @mouseup="ptzStop" @mouseleave="ptzStop"><el-icon><ArrowUp /></el-icon></el-button>
|
||||
<div style="display:flex;gap:8px">
|
||||
<el-button circle @mousedown="ptzGo('left')" @mouseup="ptzStop"><el-icon><ArrowLeft /></el-icon></el-button>
|
||||
<el-button circle type="danger" @click="ptzGo('stop')"><el-icon><Close /></el-icon></el-button>
|
||||
<el-button circle @mousedown="ptzGo('right')" @mouseup="ptzStop"><el-icon><ArrowRight /></el-icon></el-button>
|
||||
</div>
|
||||
<el-button circle @mousedown="ptzGo('down')" @mouseup="ptzStop"><el-icon><ArrowDown /></el-icon></el-button>
|
||||
<div style="display:flex;gap:8px;margin-top:8px">
|
||||
<el-button circle @mousedown="ptzGo('zoom_in')" @mouseup="ptzStop">+</el-button>
|
||||
<el-button circle @mousedown="ptzGo('zoom_out')" @mouseup="ptzStop">-</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</vol-box>
|
||||
|
||||
<!-- 实时数据 -->
|
||||
<vol-box :lazy="true" v-model="realtimeVisible" title="实时数据" :width="600" :padding="10">
|
||||
<el-table :data="realtimeValues" v-loading="realtimeLoading" stripe>
|
||||
<el-table-column prop="pointIndex" label="点位" width="80" />
|
||||
<el-table-column prop="value" label="当前值" width="120" />
|
||||
<el-table-column prop="updateTime" label="更新时间" min-width="160" />
|
||||
<el-table-column prop="interval" label="采集间隔(s)" width="100" />
|
||||
</el-table>
|
||||
<template #footer><el-button size="small" @click="realtimeVisible=false">关闭</el-button></template>
|
||||
</vol-box>
|
||||
|
||||
<!-- 设备控制 -->
|
||||
<vol-box :lazy="true" v-model="controlVisible" title="设备控制" :width="400" :padding="10">
|
||||
<el-form label-width="80px">
|
||||
<el-form-item label="点位索引"><el-input-number v-model="ctrlPointIndex" :min="0" /></el-form-item>
|
||||
<el-form-item label="目标值"><el-input-number v-model="ctrlValue" :step="0.1" /></el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<el-button type="primary" size="small" @click="controlSend">发送指令</el-button>
|
||||
<el-button size="small" @click="controlVisible=false">取消</el-button>
|
||||
</template>
|
||||
</vol-box>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import viewOptions from './base_device/options.js'
|
||||
import { ref, reactive, getCurrentInstance, watch, onMounted, h } from "vue";
|
||||
import DeviceLivePreview from "./base_device/components/DeviceLivePreview.vue";
|
||||
import PtzControlPanel from "./base_device/components/PtzControlPanel.vue";
|
||||
import RealtimeDataPanel from "./base_device/components/RealtimeDataPanel.vue";
|
||||
import DeviceControlPanel from "./base_device/components/DeviceControlPanel.vue";
|
||||
|
||||
const grid = ref(null);
|
||||
const { proxy } = getCurrentInstance()
|
||||
//http请求,proxy.http.post/get
|
||||
const { table, editFormFields, editFormOptions, searchFormFields, searchFormOptions, columns, detail, details } = reactive(viewOptions())
|
||||
|
||||
let gridRef;//对应[表.jsx]文件中this.使用方式一样
|
||||
//生成对象属性初始化
|
||||
const onInit = async ($vm) => {
|
||||
gridRef = $vm;
|
||||
//与jsx中的this.xx使用一样,只需将this.xx改为gridRef.xx
|
||||
//更多属性见:https://doc.volcore.xyz/docs/view-grid
|
||||
}
|
||||
//生成对象属性初始化后,操作明细表配置用到
|
||||
const onInited = async () => {
|
||||
// 自定义操作列:按 DeviceGroup 渲染对应按钮
|
||||
const curDev = ref(null);
|
||||
const pv = ref(false), ptz = ref(false), rt = ref(false), ctrl = ref(false);
|
||||
const GW = 'http://localhost:5100'
|
||||
let gridRef, _timer;
|
||||
|
||||
//── 对话框状态 ──
|
||||
const curDev = ref(null);
|
||||
const previewVisible = ref(false), ptzVisible = ref(false);
|
||||
const realtimeVisible = ref(false), controlVisible = ref(false);
|
||||
const wsFlv = ref(null), loading = ref(false);
|
||||
const realtimeValues = ref([]), realtimeLoading = ref(false);
|
||||
const ctrlPointIndex = ref(0), ctrlValue = ref(0);
|
||||
|
||||
//── 预览取流 ──
|
||||
const openPreview = async (d) => {
|
||||
curDev.value = d; wsFlv.value = null; loading.value = true; previewVisible.value = true;
|
||||
try {
|
||||
const r = await fetch(`${GW}/api/gateway/streams/${d.adapterCode}/${d.sourceId}/live`);
|
||||
const j = await r.json();
|
||||
wsFlv.value = j.wsFlv || j.httpFlv;
|
||||
} catch {} finally { loading.value = false }
|
||||
}
|
||||
|
||||
//── 云台 ──
|
||||
const ptzSend = (dir, speed = 0.5) => {
|
||||
fetch(`${GW}/api/gateway/streams/${curDev.value?.adapterCode}/${curDev.value?.sourceId}/ptz`, {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ direction: dir, action: dir === 'stop' ? 'stop' : 'continuous', speed })
|
||||
})
|
||||
}
|
||||
const ptzGo = (d) => ptzSend(d)
|
||||
const ptzStop = () => ptzSend('stop')
|
||||
|
||||
//── 实时数据 ──
|
||||
const fetchRealtime = async () => {
|
||||
if (!curDev.value) return; realtimeLoading.value = true;
|
||||
try {
|
||||
const r = await fetch(`${GW}/api/gateway/realtime/${curDev.value.adapterCode}/${curDev.value.sourceId}`);
|
||||
realtimeValues.value = await r.json();
|
||||
} catch {} finally { realtimeLoading.value = false }
|
||||
}
|
||||
const openRealtime = (d) => { curDev.value = d; realtimeVisible.value = true; fetchRealtime(); _timer = setInterval(fetchRealtime, 5000) }
|
||||
watch(realtimeVisible, v => { if (!v) clearInterval(_timer) })
|
||||
|
||||
//── 控制 ──
|
||||
const controlSend = () => {
|
||||
fetch(`${GW}/api/gateway/realtime/${curDev.value?.adapterCode}/control`, {
|
||||
method: 'POST', headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ deviceId: curDev.value?.sourceId, pointIndex: ctrlPointIndex.value, value: ctrlValue.value })
|
||||
})
|
||||
controlVisible.value = false
|
||||
}
|
||||
const openControl = (d) => { curDev.value = d; controlVisible.value = true }
|
||||
|
||||
//── 框架钩子 ──
|
||||
const onInit = async ($vm) => { gridRef = $vm; }
|
||||
const onInited = async () => {
|
||||
// 自定义操作列
|
||||
columns.push({
|
||||
title: '操作', field: '_actions', width: 300, align: 'left', fixed: 'right',
|
||||
render: (_h, { row }) => {
|
||||
if (row.DeviceGroup === '视频设备') {
|
||||
return _h('div', [
|
||||
_h('el-button', { size: 'small', type: 'primary',
|
||||
onClick: () => { curDev.value = row; pv.value = true }
|
||||
h('el-button', { size: 'small', type: 'primary',
|
||||
onClick: () => openPreview(row)
|
||||
}, { default: () => '预览' }),
|
||||
_h('el-button', { size: 'small',
|
||||
onClick: () => { curDev.value = row; ptz.value = true }
|
||||
h('el-button', { size: 'small',
|
||||
onClick: () => { curDev.value = row; ptzVisible.value = true }
|
||||
}, { default: () => '云台' }),
|
||||
_h(DeviceLivePreview, { modelValue: pv.value, 'onUpdate:modelValue': v => pv.value = v, device: curDev.value }),
|
||||
_h(PtzControlPanel, { modelValue: ptz.value, 'onUpdate:modelValue': v => ptz.value = v, device: curDev.value }),
|
||||
]);
|
||||
}
|
||||
if (row.DeviceGroup === 'IoT设备') {
|
||||
return _h('div', [
|
||||
_h('el-button', { size: 'small', type: 'primary',
|
||||
onClick: () => { curDev.value = row; rt.value = true }
|
||||
h('el-button', { size: 'small', type: 'primary',
|
||||
onClick: () => openRealtime(row)
|
||||
}, { default: () => '实时数据' }),
|
||||
_h('el-button', { size: 'small',
|
||||
onClick: () => { curDev.value = row; ctrl.value = true }
|
||||
h('el-button', { size: 'small',
|
||||
onClick: () => openControl(row)
|
||||
}, { default: () => '控制' }),
|
||||
_h(RealtimeDataPanel, { modelValue: rt.value, 'onUpdate:modelValue': v => rt.value = v, device: curDev.value }),
|
||||
_h(DeviceControlPanel, { modelValue: ctrl.value, 'onUpdate:modelValue': v => ctrl.value = v, device: curDev.value }),
|
||||
]);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
const gcol = columns.find(c => c.field === 'DeviceGroup');
|
||||
if (gcol) gcol.hidden = false;
|
||||
}
|
||||
const searchBefore = async (param) => {
|
||||
//界面查询前,可以给param.wheres添加查询参数
|
||||
//返回false,则不会执行查询
|
||||
return true;
|
||||
}
|
||||
const searchAfter = async (rows, result) => {
|
||||
return true;
|
||||
}
|
||||
const addBefore = async (formData) => {
|
||||
//新建保存前formData为对象,包括明细表,可以给给表单设置值,自己输出看formData的值
|
||||
return true;
|
||||
}
|
||||
const updateBefore = async (formData) => {
|
||||
//编辑保存前formData为对象,包括明细表、删除行的Id
|
||||
return true;
|
||||
}
|
||||
const rowClick = ({ row, column, event }) => {
|
||||
//查询界面点击行事件
|
||||
// grid.value.toggleRowSelection(row); //单击行时选中当前行;
|
||||
}
|
||||
const modelOpenBefore = async (row) => {//弹出框打开后方法
|
||||
return true;//返回false,不会打开弹出框
|
||||
}
|
||||
const modelOpenAfter = (row) => {
|
||||
//弹出框打开后方法,设置表单默认值,按钮操作等
|
||||
}
|
||||
//监听表单输入,做实时计算
|
||||
//watch(() => editFormFields.字段,(newValue, oldValue) => { })
|
||||
//对外暴露数据
|
||||
const searchBefore = async (param) => { return true; }
|
||||
const searchAfter = async (rows, result) => { return true; }
|
||||
const addBefore = async (formData) => { return true; }
|
||||
const updateBefore = async (formData) => { return true; }
|
||||
const rowClick = ({ row, column, event }) => {}
|
||||
const modelOpenBefore = async (row) => { return true; }
|
||||
const modelOpenAfter = (row) => {}
|
||||
defineExpose({})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user