V4 前端改造: 11个组件+gateway.js+extension注入

This commit is contained in:
2026-05-17 10:45:40 +08:00
parent 12ace53650
commit b69d6976c3
32 changed files with 1731 additions and 1 deletions

View File

@@ -0,0 +1,50 @@
import request from '@/uitils/request'
// 网关 B 组接口封装。前端直连网关 :5100。
// 生产环境通过 nginx 反向代理 /api/gateway/* → 网关地址。
const gwBase = '/api/gateway'
/// B6a: 获取实时视频流地址
export const getLiveStream = (adapter, deviceId) =>
request({ url: `${gwBase}/streams/${adapter}/${deviceId}/live`, method: 'get' })
/// B6b: 获取回放流地址
export const getPlaybackStream = (adapter, deviceId, start, end) =>
request({ url: `${gwBase}/streams/${adapter}/${deviceId}/playback`, method: 'get', params: { start, end } })
/// 获取截图
export const getSnapshot = (adapter, deviceId) =>
request({ url: `${gwBase}/streams/${adapter}/${deviceId}/snapshot`, method: 'post' })
/// B7: 云台方向控制
export const ptzControl = (adapter, deviceId, direction, speed = 0.5) =>
request({ url: `${gwBase}/streams/${adapter}/${deviceId}/ptz`, method: 'post', data: { direction, action: 'continuous', speed } })
/// B7: 云台停止
export const ptzStop = (adapter, deviceId) =>
request({ url: `${gwBase}/streams/${adapter}/${deviceId}/ptz`, method: 'post', data: { action: 'stop' } })
/// B4: 获取实时点位值
export const getRealtime = (adapter, deviceId) =>
request({ url: `${gwBase}/realtime/${adapter}/${deviceId}`, method: 'get' })
/// B5: 设备控制写值
export const controlDevice = (adapter, deviceId, pointIndex, value) =>
request({ url: `${gwBase}/realtime/${adapter}/control`, method: 'post', data: { deviceId, pointIndex, value } })
/// B8: 分页查询告警
export const getAlarms = (adapter, params) =>
request({ url: `${gwBase}/alarms/${adapter}`, method: 'get', params })
/// B9: 告警确认
export const confirmAlarm = (adapter, alarmId) =>
request({ url: `${gwBase}/alarms/${adapter}/${alarmId}/confirm`, method: 'post' })
/// B9: 告警结束
export const endAlarm = (adapter, alarmId) =>
request({ url: `${gwBase}/alarms/${adapter}/${alarmId}/end`, method: 'post' })
/// B3: 手动触发同步
export const triggerSync = (adapter) =>
request({ url: `${gwBase}/devices/sync`, method: 'post', params: { adapter } })

View File

@@ -0,0 +1,72 @@
/**
* base_device 页面操作列扩展
* 按 DeviceGroup 动态渲染对应的操作按钮组件
* 框架升级不覆盖此文件extension 目录受保护)
*/
import VideoDeviceActions from '@/views/warehouse/base_device/components/VideoDeviceActions.vue'
import IoTDeviceActions from '@/views/warehouse/base_device/components/IoTDeviceActions.vue'
import AccessDeviceActions from '@/views/warehouse/base_device/components/AccessDeviceActions.vue'
import BarrierDeviceActions from '@/views/warehouse/base_device/components/BarrierDeviceActions.vue'
import AlarmDeviceActions from '@/views/warehouse/base_device/components/AlarmDeviceActions.vue'
import DeviceLivePreview from '@/views/warehouse/base_device/components/DeviceLivePreview.vue'
import PtzControlPanel from '@/views/warehouse/base_device/components/PtzControlPanel.vue'
import RealtimeDataPanel from '@/views/warehouse/base_device/components/RealtimeDataPanel.vue'
import DeviceControlPanel from '@/views/warehouse/base_device/components/DeviceControlPanel.vue'
import DeviceEditDialog from '@/views/warehouse/base_device/components/DeviceEditDialog.vue'
import MapBindingPanel from '@/views/warehouse/base_device/components/MapBindingPanel.vue'
// 按 DeviceGroup 映射操作组件
const actionMap = {
'视频设备': 'VideoDeviceActions',
'IoT设备': 'IoTDeviceActions',
'门禁设备': 'AccessDeviceActions',
'道闸设备': 'BarrierDeviceActions',
'报警设备': 'AlarmDeviceActions',
}
export default {
components: {
VideoDeviceActions, IoTDeviceActions, AccessDeviceActions, BarrierDeviceActions, AlarmDeviceActions,
DeviceLivePreview, PtzControlPanel, RealtimeDataPanel, DeviceControlPanel, DeviceEditDialog, MapBindingPanel
},
data() {
return {
currentDevice: null,
dialogs: { preview: false, ptz: false, realtime: false, control: false, edit: false, map: false }
}
},
// 替换框架操作列
slots: {
'col-action': (h, { row }) => {
const compName = actionMap[row.deviceGroup]
if (!compName) return null
// 渲染自定义按钮组,绑定事件
return h(compName, {
props: { row },
on: {
preview: () => this.openDialog('preview', row),
ptz: () => this.openDialog('ptz', row),
playback: () => console.log('playback', row),
snapshot: () => console.log('snapshot', row),
syncChannels: () => console.log('syncChannels', row),
realtime: () => this.openDialog('realtime', row),
control: () => this.openDialog('control', row),
refresh: () => this.$emit('refresh'),
alarms: () => console.log('alarms', row),
}
})
}
},
methods: {
openDialog(name, device) {
this.currentDevice = device
this.dialogs[name] = true
},
onRefresh() {
this.$emit('refresh')
}
}
}

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -0,0 +1,75 @@
/*****************************************************************************************
** Author:jxx 2023
** QQ:283591387
** 框架文档: http://doc.volcore.xyz/
*****************************************************************************************/
//此js文件是用来自定义扩展业务代码在当前[表.vue]文件中也可以实现业务处理
let extension = {
components: {
//查询界面扩展组件
gridHeader: '',
gridBody: '',
gridFooter: '',
//新建、编辑弹出框扩展组件
modelHeader: '',
modelBody: '',
modelRight: '',
modelFooter: ''
},
tableAction: '', //指定某张表的权限(这里填写表名,默认不用填写)
buttons: { view: [], box: [], detail: [] }, //扩展的按钮
methods: {
//下面这些方法可以保留也可以删除
onInit() { //框架初始化配置前,
//示例:在按钮的最前面添加一个按钮
// this.buttons.unshift({ //也可以用push或者splice方法来修改buttons数组
// name: '按钮', //按钮名称
// icon: 'el-icon-document', //按钮图标https://element.eleme.cn/#/zh-CN/component/icon
// type: 'primary', //按钮样式:https://element-plus.gitee.io/zh-CN/component/button.html
// //color:"#eee",//自定义按钮颜色
// onClick: function () {
// this.$Message.success('点击了按钮');
// }
// });
//示例:设置修改新建、编辑弹出框字段标签的长度
// this.boxOptions.labelWidth = 150;
},
onInited() {
//框架初始化配置后
//如果要配置明细表,在此方法操作
//this.detailOptions.columns.forEach(column=>{ });
},
searchBefore(param) {
//界面查询前,可以给param.wheres添加查询参数
//返回false则不会执行查询
return true;
},
searchAfter(result) {
//查询后result返回的查询数据,可以在显示到表格前处理表格的值
return true;
},
addBefore(formData) {
//新建保存前formData为对象包括明细表可以给给表单设置值自己输出看formData的值
return true;
},
updateBefore(formData) {
//编辑保存前formData为对象包括明细表、删除行的Id
return true;
},
rowClick({ row, column, event }) {
//查询界面点击行事件
// this.$refs.table.$refs.table.toggleRowSelection(row); //单击行时选中当前行;
},
modelOpenAfter(row) {
//点击编辑、新建按钮弹出框后,可以在此处写逻辑,如,从后台获取数据
//(1)判断是编辑还是新建操作: this.currentAction=='Add';
//(2)给弹出框设置默认值
//(3)this.editFormFields.字段='xxx';
//如果需要给下拉框设置默认值请遍历this.editFormOptions找到字段配置对应data属性的key值
//看不懂就把输出看console.log(this.editFormOptions)
}
}
};
export default extension;

View File

@@ -620,7 +620,31 @@ let viewgird = [
meta: {
multiPage: true,
},
}]
} ,{
path: '/video_channel',
name: 'video_channel',
component: () => import('@/views/warehouse/device_manager/video_channel.vue')
} ,{
path: '/iot_devicedata',
name: 'iot_devicedata',
component: () => import('@/views/warehouse/device_manager/iot_devicedata.vue')
} ,{
path: '/iot_alarm',
name: 'iot_alarm',
component: () => import('@/views/warehouse/device_manager/iot_alarm.vue')
} ,{
path: '/gateway_nodes',
name: 'gateway_nodes',
component: () => import('@/views/warehouse/device_manager/gateway_nodes.vue')
} ,{
path: '/video_record',
name: 'video_record',
component: () => import('@/views/warehouse/device_manager/video_record.vue')
} ,{
path: '/base_device',
name: 'base_device',
component: () => import('@/views/warehouse/device_manager/base_device.vue')
}]
//上面的demo、MES开头的都是示例菜单可以任意删除
export default viewgird

View File

@@ -0,0 +1,2 @@
<template><div><el-button size="small" text disabled>Access (Phase 3)</el-button></div></template>
<script setup>defineProps({ row: Object })</script>

View File

@@ -0,0 +1,2 @@
<template><div><el-button size="small" text disabled>Alarm (Phase 3)</el-button></div></template>
<script setup>defineProps({ row: Object })</script>

View File

@@ -0,0 +1,2 @@
<template><div><el-button size="small" text disabled>Barrier (Phase 3)</el-button></div></template>
<script setup>defineProps({ row: Object })</script>

View File

@@ -0,0 +1,28 @@
<template>
<el-dialog v-model="visible" title="设备控制" width="400px">
<el-form label-width="80px">
<el-form-item label="点位索引">
<el-input-number v-model="pointIndex" :min="0" />
</el-form-item>
<el-form-item label="目标值">
<el-input-number v-model="value" :step="0.1" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="send">发送指令</el-button>
<el-button @click="visible=false">取消</el-button>
</template>
</el-dialog>
</template>
<script setup>
import { ref, computed } from 'vue'
import { controlDevice } from '@/api/gateway'
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 pointIndex = ref(0), value = ref(0)
const send = async () => {
await controlDevice(props.device?.adapterCode, props.device?.sourceId, pointIndex.value, value.value)
visible.value = false
}
</script>

View File

@@ -0,0 +1,25 @@
<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>
<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:'启用' })
watch(() => props.device, d => { if (d) Object.assign(f, d) })
const save = () => { emit('saved'); visible.value = false }
</script>

View File

@@ -0,0 +1,28 @@
<template>
<el-dialog v-model="visible" title="实时预览" width="960px" @close="stop">
<div style="min-height:300px;display:flex;align-items:center;justify-content:center;background:#000">
<div v-if="!wsFlv" style="color:#fff">{{ loading ? '加载中...' : '无法获取流地址' }}</div>
<video v-else ref="playerRef" :src="wsFlv" autoplay muted controls style="width:100%;height:500px;background:#000" />
</div>
<template #footer><el-button @click="visible=false">关闭</el-button></template>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch } from 'vue'
import { getLiveStream } from '@/api/gateway'
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 stream = ref(null), loading = ref(false)
const wsFlv = computed(() => stream.value?.wsFlv || stream.value?.httpFlv)
const stop = () => { stream.value = null }
watch(() => props.device, async (d) => {
if (d && visible.value) {
loading.value = true
try { stream.value = await getLiveStream(d.adapterCode, d.sourceId) } catch(e) {}
finally { loading.value = false }
}
}, { immediate: true })
</script>

View File

@@ -0,0 +1,17 @@
<template>
<div style="display:flex;gap:4px;flex-wrap:wrap">
<el-button size="small" type="primary" @click="$emit('realtime')">实时数据</el-button>
<el-button v-if="isControl" size="small" @click="$emit('control')">设备控制</el-button>
<el-button size="small" @click="$emit('refresh')">刷新</el-button>
<el-button size="small" type="warning" @click="$emit('alarms')">查看告警</el-button>
</div>
</template>
<script setup>
import { computed } from 'vue'
const props = defineProps({ row: { type: Object, default: () => ({}) } })
defineEmits(['realtime','control','refresh','alarms'])
// 通过 ExtraData 判断是否为控制点
const isControl = computed(() => {
try { return JSON.parse(props.row?.extraData || '{}')?.isControlPoint === true } catch { return false }
})
</script>

View File

@@ -0,0 +1,19 @@
<template>
<el-dialog v-model="visible" title="地图绑定" width="500px">
<el-form :model="f" label-width="100px">
<el-form-item label="VgoMap模型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 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 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>

View File

@@ -0,0 +1,29 @@
<template>
<el-dialog v-model="visible" title="云台控制" width="320px">
<div style="display:flex;flex-direction:column;align-items:center;gap:4px">
<el-button circle @mousedown="go('up')" @mouseup="stop" @mouseleave="stop"><el-icon><ArrowUp /></el-icon></el-button>
<div style="display:flex;gap:8px">
<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 style="display:flex;gap:8px;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'
import { ptzControl, ptzStop } from '@/api/gateway'
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 = (d) => {
if (d === 'stop') ptzStop(props.device?.adapterCode, props.device?.sourceId)
else ptzControl(props.device?.adapterCode, props.device?.sourceId, d)
}
const stop = () => go('stop')
</script>

View File

@@ -0,0 +1,33 @@
<template>
<el-dialog v-model="visible" title="实时数据" width="600px">
<el-table :data="values" v-loading="loading" stripe>
<el-table-column prop="pointIndex" label="点位" width="80" />
<el-table-column prop="value" label="当前值" width="120">
<template #default="{row}">{{ row.value }}{{ row.unit || '' }}</template>
</el-table-column>
<el-table-column prop="updateTime" label="更新时间" min-width="160" />
<el-table-column prop="interval" label="采集间隔(s)" width="100" />
</el-table>
<template #footer><el-button @click="visible=false">关闭</el-button></template>
</el-dialog>
</template>
<script setup>
import { ref, computed, watch, onUnmounted } from 'vue'
import { getRealtime } from '@/api/gateway'
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 values = ref([]), loading = ref(false)
let timer = null
const fetch = async () => {
if (!props.device) return
loading.value = true
try { values.value = await getRealtime(props.device.adapterCode, props.device.sourceId) } catch {}
finally { loading.value = false }
}
watch(() => props.device, () => { if (visible.value) { fetch(); timer = setInterval(fetch, 5000) } }, { immediate: true })
watch(visible, v => { if (v) { fetch(); timer = setInterval(fetch, 5000) } else { clearInterval(timer) } })
onUnmounted(() => clearInterval(timer))
</script>

View File

@@ -0,0 +1,23 @@
<template>
<div style="display:flex;gap:4px;flex-wrap:wrap">
<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>
<el-button v-if="row?.isParent==='是'" size="small" type="warning" @click="$emit('syncChannels')">
同步通道
</el-button>
</div>
</template>
<script setup>
defineProps({ row: { type: Object, default: () => ({}) } })
defineEmits(['preview','ptz','playback','snapshot','syncChannels'])
</script>

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@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"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/base_device.jsx";
import viewOptions from './base_device/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,153 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'DeviceId',
footer: "Foots",
cnName: '设备管理',
name: 'base_device',
newTabEdit: false,
url: "/base_device/",
sortName: "DeviceName",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {"DeviceName":"","DeviceCategory":"","DeviceGroup":"","IsParent":"","PointId":"","Location":"","MapModelId":"","Enable":"","Remark":""};
const editFormOptions = [[{"title":"设备名称","required":true,"field":"DeviceName","colSize":50.0},
{"dataKey":"设备种类","data":[],"title":"设备种类(数据字典)","required":true,"field":"DeviceCategory","colSize":50.0,"type":"select"}],
[{"dataKey":"设备分组","data":[],"title":"设备分组(数据字典)","required":true,"field":"DeviceGroup","colSize":50.0,"type":"select"},
{"dataKey":"是否父设备","data":[],"title":"是否父设备(数据字典)","required":true,"field":"IsParent","colSize":50.0,"type":"select"}],
[{"title":"所属点位ID","field":"PointId","colSize":50.0,"type":"number"},
{"title":"安装位置","field":"Location","colSize":50.0}],
[{"title":"三维地图模型ID","field":"MapModelId","colSize":50.0},
{"dataKey":"启用状态","data":[],"title":"启用状态(数据字典)","field":"Enable","colSize":50.0,"type":"select"}],
[{"title":"备注","field":"Remark","colSize":100.0,"type":"textarea"}]];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'DeviceId',title:'设备ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'DeviceName',title:'设备名称',type:'string',link:true,width:120,require:true,align:'left'},
{field:'AdapterCode',title:'来源适配器(类型:实例)',type:'string',width:110,hidden:true,require:true,align:'left'},
{field:'SourceId',title:'源系统设备ID',type:'string',width:120,require:true,align:'left'},
{field:'DeviceCategory',title:'设备种类(数据字典)',type:'string',bind:{ key:'设备种类',data:[]},width:110,require:true,align:'left'},
{field:'DeviceGroup',title:'设备分组(数据字典)',type:'string',bind:{ key:'设备分组',data:[]},width:110,hidden:true,require:true,align:'left'},
{field:'PointId',title:'所属点位ID',type:'int',width:110,hidden:true,align:'left'},
{field:'GatewayNodeId',title:'所属网关节点ID',type:'int',width:110,hidden:true,align:'left'},
{field:'IsParent',title:'是否父设备(数据字典)',type:'string',bind:{ key:'是否父设备',data:[]},width:110,require:true,align:'left'},
{field:'ParentDeviceId',title:'父设备ID(自引用,子设备挂父设备下)',type:'int',width:110,hidden:true,align:'left'},
{field:'IsOnline',title:'在线状态(数据字典)',type:'string',bind:{ key:'在线状态',data:[]},width:110,require:true,align:'left'},
{field:'IpAddress',title:'IP地址',type:'string',width:110,align:'left'},
{field:'Port',title:'端口',type:'int',width:110,align:'left'},
{field:'Location',title:'安装位置',type:'string',width:180,align:'left'},
{field:'Lat',title:'纬度',type:'decimal',width:110,align:'left'},
{field:'Lng',title:'经度',type:'decimal',width:110,align:'left'},
{field:'MapModelId',title:'三维地图模型ID',type:'string',width:120,align:'left'},
{field:'MapModelScale',title:'模型缩放比例',type:'decimal',width:110,align:'left'},
{field:'MapModelRotation',title:'模型旋转角度(JSON)',type:'string',width:120,align:'left'},
{field:'ExtraData',title:'适配器扩展数据JSON(Owl/MC4/门禁字段均存于此)',type:'string',width:110,align:'left'},
{field:'LastSyncTime',title:'上次同步时间',type:'datetime',width:110,align:'left'},
{field:'Enable',title:'启用状态(数据字典)',type:'string',bind:{ key:'启用状态',data:[]},width:110,align:'left'},
{field:'Remark',title:'备注',type:'string',width:150,align:'left'},
{field:'CreateID',title:'创建人ID',type:'int',width:80,hidden:true,align:'left'},
{field:'Creator',title:'创建人',type:'string',width:100,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'},
{field:'ModifyID',title:'修改人ID',type:'int',width:80,hidden:true,align:'left'},
{field:'Modifier',title:'修改人',type:'string',width:100,align:'left'},
{field:'ModifyDate',title:'修改时间',type:'datetime',width:110,align:'left'}];
const detail ={columns:[]};
const details = [ {
cnName: '视频通道',
table: 'video_channel',
columns: [{field:'ChannelId',title:'通道记录ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'OwlChannelId',title:'Owl系统通道ID',type:'string',width:120,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联Base_Device设备ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'OwlStreamApp',title:'Owl流应用名',type:'string',width:110,align:'left'},
{field:'OwlStreamName',title:'Owl流名称',type:'string',width:120,align:'left'},
{field:'HasPtz',title:'是否支持云台',type:'byte',width:110,align:'left'},
{field:'HasRecording',title:'是否支持录像',type:'byte',width:110,align:'left'},
{field:'RecordMode',title:'录像模式',type:'int',width:110,align:'left'},
{field:'SnapshotUrl',title:'快照地址',type:'string',width:150,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'}],
sortName: 'ChannelId',
key: 'ChannelId',
buttons:[],
delKeys:[],
detail:{
cnName: '设备管理_录像记录',
table: 'video_record',
firstTable: 'base_device',
secondTable: 'video_channel',
secondKey: 'ChannelId',
sortName: 'ChannelId',
key: 'RecordId',
buttons:[],
delKeys:[],
columns: [{field:'RecordId',title:'录像记录ID',type:'int',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'ChannelId',title:'关联通道ID',type:'int',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'OwlRecordId',title:'Owl录像记录ID',type:'int',width:110,readonly:true,require:true,align:'left'},
{field:'App',title:'应用名',type:'string',width:110,readonly:true,align:'left'},
{field:'Stream',title:'流ID',type:'string',width:120,readonly:true,align:'left'},
{field:'StartedAt',title:'录像开始时间',type:'datetime',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'EndedAt',title:'录像结束时间',type:'datetime',width:110,readonly:true,align:'left'},
{field:'Duration',title:'录像时长(秒)',type:'decimal',width:110,readonly:true,align:'left'},
{field:'FilePath',title:'文件路径',type:'string',width:150,readonly:true,align:'left'},
{field:'FileSize',title:'文件大小(字节)',type:'bigint',width:110,readonly:true,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,readonly:true,align:'left'},]
}
},
{
cnName: '数据归档',
table: 'iot_devicedata',
columns: [{field:'DataId',title:'数据记录ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联设备ID(子设备/点位)',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'PointValue',title:'点位数值',type:'decimal',width:110,align:'left'},
{field:'UpdateTime',title:'数据更新时间',type:'datetime',width:110,require:true,align:'left'},
{field:'Interval',title:'采集间隔(毫秒)',type:'int',width:110,align:'left'},
{field:'ArchiveType',title:'归档类型(1小时/2日)',type:'int',width:110,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,hidden:true,align:'left'}],
sortName: 'UpdateTime',
key: 'DataId',
buttons:[],
delKeys:[],
detail:null
},
{
cnName: '告警记录',
table: 'iot_alarm',
columns: [{field:'AlarmId',title:'告警ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'SourceAlarmId',title:'源系统告警ID',type:'string',width:120,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联设备ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'AlarmType',title:'告警类型',type:'int',width:110,align:'left'},
{field:'AlarmLevel',title:'告警等级(数据字典:提示/普通/重要/紧急)',type:'string',bind:{ key:'告警等级',data:[]},width:110,hidden:true,align:'left'},
{field:'AlarmDesc',title:'告警描述',type:'string',width:150,align:'left'},
{field:'AlarmValue',title:'触发值',type:'decimal',width:110,align:'left'},
{field:'StartTime',title:'告警开始时间',type:'datetime',width:110,hidden:true,require:true,align:'left'},
{field:'EndTime',title:'告警结束时间',type:'datetime',width:110,align:'left'},
{field:'ConfirmTime',title:'确认时间',type:'datetime',width:110,align:'left'},
{field:'ConfirmUser',title:'确认人',type:'string',width:110,align:'left'},
{field:'State',title:'状态(数据字典:未确认/已确认/已结束)',type:'string',bind:{ key:'告警状态',data:[]},width:110,align:'left'},
{field:'AdapterCode',title:'来源适配器',type:'string',width:110,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'}],
sortName: 'StartTime',
key: 'AlarmId',
buttons:[],
delKeys:[],
detail:null
}];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@qq.com
*业务请在@/extension/warehouse/device_manager/gateway_nodes.jsx或gateway_nodes.vue文件编写
*新版本支持vue或.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
-->
<template>
<view-grid ref="grid"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/gateway_nodes.jsx";
import viewOptions from './gateway_nodes/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,59 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'NodeId',
footer: "Foots",
cnName: '设备管理_网关节点',
name: 'gateway_nodes',
newTabEdit: false,
url: "/gateway_nodes/",
sortName: "NodeId",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {"NodeCode":"","NodeName":"","NodeToken":"","Remark":""};
const editFormOptions = [[{"title":"网关名称","required":true,"field":"NodeName","colSize":50.0},
{"title":"网关唯一编码","required":true,"field":"NodeCode","colSize":50.0}],
[{"title":"认证令牌","required":true,"field":"NodeToken","colSize":100.0}],
[{"title":"备注","field":"Remark","colSize":100.0,"type":"textarea"}]];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'NodeId',title:'网关节点ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'NodeCode',title:'网关唯一编码',type:'string',width:110,hidden:true,require:true,align:'left'},
{field:'NodeName',title:'网关名称',type:'string',width:120,require:true,align:'left'},
{field:'NodeToken',title:'认证令牌',type:'string',width:120,require:true,align:'left'},
{field:'AdapterTypes',title:'支持的适配器类型(网关上报)',type:'string',width:180,align:'left'},
{field:'BaseUrl',title:'网关自身地址(网关上报)',type:'string',width:180,align:'left'},
{field:'LastHeartbeat',title:'上次心跳时间',type:'datetime',width:110,align:'left'},
{field:'IsOnline',title:'在线状态(数据字典:在线/离线)',type:'string',width:110,hidden:true,align:'left'},
{field:'Enable',title:'启用状态(数据字典:启用/禁用)',type:'string',width:110,align:'left'},
{field:'Remark',title:'备注',type:'string',width:150,align:'left'},
{field:'CreateID',title:'创建人ID',type:'int',width:80,hidden:true,align:'left'},
{field:'Creator',title:'创建人',type:'string',width:100,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'},
{field:'ModifyID',title:'修改人ID',type:'int',width:80,hidden:true,align:'left'},
{field:'Modifier',title:'修改人',type:'string',width:100,align:'left'},
{field:'ModifyDate',title:'修改时间',type:'datetime',width:110,align:'left'}];
const detail ={columns:[]};
const details = [];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details
};
}

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@qq.com
*业务请在@/extension/warehouse/device_manager/iot_alarm.jsx或iot_alarm.vue文件编写
*新版本支持vue或.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
-->
<template>
<view-grid ref="grid"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/iot_alarm.jsx";
import viewOptions from './iot_alarm/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,55 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'AlarmId',
editTable:true ,
footer: "Foots",
cnName: '设备管理_告警记录',
name: 'iot_alarm',
newTabEdit: false,
url: "/iot_alarm/",
sortName: "StartTime",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {};
const editFormOptions = [];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'AlarmId',title:'告警ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'SourceAlarmId',title:'源系统告警ID',type:'string',width:120,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联设备ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'AlarmType',title:'告警类型',type:'int',width:110,align:'left'},
{field:'AlarmLevel',title:'告警等级(数据字典:提示/普通/重要/紧急)',type:'string',bind:{ key:'告警等级',data:[]},width:110,hidden:true,align:'left'},
{field:'AlarmDesc',title:'告警描述',type:'string',width:150,align:'left'},
{field:'AlarmValue',title:'触发值',type:'decimal',width:110,align:'left'},
{field:'StartTime',title:'告警开始时间',type:'datetime',width:110,hidden:true,require:true,align:'left'},
{field:'EndTime',title:'告警结束时间',type:'datetime',width:110,align:'left'},
{field:'ConfirmTime',title:'确认时间',type:'datetime',width:110,align:'left'},
{field:'ConfirmUser',title:'确认人',type:'string',width:110,align:'left'},
{field:'State',title:'状态(数据字典:未确认/已确认/已结束)',type:'string',bind:{ key:'告警状态',data:[]},width:110,align:'left'},
{field:'AdapterCode',title:'来源适配器',type:'string',width:110,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'}];
const detail ={columns:[]};
const details = [];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details
};
}

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@qq.com
*业务请在@/extension/warehouse/device_manager/iot_devicedata.jsx或iot_devicedata.vue文件编写
*新版本支持vue或.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
-->
<template>
<view-grid ref="grid"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/iot_devicedata.jsx";
import viewOptions from './iot_devicedata/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,48 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'DataId',
editTable:true ,
footer: "Foots",
cnName: '设备管理_数据归档',
name: 'iot_devicedata',
newTabEdit: false,
url: "/iot_devicedata/",
sortName: "UpdateTime",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {};
const editFormOptions = [];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'DataId',title:'数据记录ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联设备ID(子设备/点位)',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'PointValue',title:'点位数值',type:'decimal',width:110,align:'left'},
{field:'UpdateTime',title:'数据更新时间',type:'datetime',width:110,require:true,align:'left'},
{field:'Interval',title:'采集间隔(毫秒)',type:'int',width:110,align:'left'},
{field:'ArchiveType',title:'归档类型(1小时/2日)',type:'int',width:110,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,hidden:true,align:'left'}];
const detail ={columns:[]};
const details = [];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details
};
}

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@qq.com
*业务请在@/extension/warehouse/device_manager/video_channel.jsx或video_channel.vue文件编写
*新版本支持vue或.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
-->
<template>
<view-grid ref="grid"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/video_channel.jsx";
import viewOptions from './video_channel/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,67 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'ChannelId',
editTable:true ,
footer: "Foots",
cnName: '设备管理_视频通道',
name: 'video_channel',
newTabEdit: false,
url: "/video_channel/",
sortName: "ChannelId",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {};
const editFormOptions = [];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'ChannelId',title:'通道记录ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'OwlChannelId',title:'Owl系统通道ID',type:'string',width:120,hidden:true,require:true,align:'left'},
{field:'DeviceId',title:'关联Base_Device设备ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'OwlStreamApp',title:'Owl流应用名',type:'string',width:110,align:'left'},
{field:'OwlStreamName',title:'Owl流名称',type:'string',width:120,align:'left'},
{field:'HasPtz',title:'是否支持云台',type:'byte',width:110,align:'left'},
{field:'HasRecording',title:'是否支持录像',type:'byte',width:110,align:'left'},
{field:'RecordMode',title:'录像模式',type:'int',width:110,align:'left'},
{field:'SnapshotUrl',title:'快照地址',type:'string',width:150,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'}];
const detail = {
cnName: '录像记录',
table: 'video_record',
columns: [{field:'RecordId',title:'录像记录ID',type:'int',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'ChannelId',title:'关联通道ID',type:'int',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'OwlRecordId',title:'Owl录像记录ID',type:'int',width:110,readonly:true,require:true,align:'left'},
{field:'App',title:'应用名',type:'string',width:110,readonly:true,align:'left'},
{field:'Stream',title:'流ID',type:'string',width:120,readonly:true,align:'left'},
{field:'StartedAt',title:'录像开始时间',type:'datetime',width:110,hidden:true,readonly:true,require:true,align:'left'},
{field:'EndedAt',title:'录像结束时间',type:'datetime',width:110,readonly:true,align:'left'},
{field:'Duration',title:'录像时长(秒)',type:'decimal',width:110,readonly:true,align:'left'},
{field:'FilePath',title:'文件路径',type:'string',width:150,readonly:true,align:'left'},
{field:'FileSize',title:'文件大小(字节)',type:'bigint',width:110,readonly:true,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,readonly:true,align:'left'}],
sortName: 'RecordId',
key: 'RecordId'
};
const details = [];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details
};
}

View File

@@ -0,0 +1,82 @@
<!--
*Authorjxx
*Date{Date}
*Contact283591387@qq.com
*业务请在@/extension/warehouse/device_manager/video_record.jsx或video_record.vue文件编写
*新版本支持vue或.jsx]文件编写业务,文档见:https://doc.volcore.xyz/docs/view-grid、https://doc.volcore.xyz/docs/web
-->
<template>
<view-grid ref="grid"
:columns="columns"
:detail="detail"
:details="details"
:editFormFields="editFormFields"
:editFormOptions="editFormOptions"
:searchFormFields="searchFormFields"
:searchFormOptions="searchFormOptions"
:table="table"
:extend="extend"
:onInit="onInit"
:onInited="onInited"
:searchBefore="searchBefore"
:searchAfter="searchAfter"
:addBefore="addBefore"
:updateBefore="updateBefore"
:rowClick="rowClick"
:modelOpenBefore="modelOpenBefore"
:modelOpenAfter="modelOpenAfter">
<!-- 自定义组件数据槽扩展更多数据槽slot见文档 -->
<template #gridHeader>
</template>
</view-grid>
</template>
<script setup lang="jsx">
import extend from "@/extension/warehouse/device_manager/video_record.jsx";
import viewOptions from './video_record/options.js'
import { ref, reactive, getCurrentInstance, watch, onMounted } from "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 () => {
}
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) => { })
//对外暴露数据
defineExpose({})
</script>

View File

@@ -0,0 +1,52 @@
// *Authorjxx
// *Contact283591387@qq.com
// *代码由框架生成,任何更改都可能导致被代码生成器覆盖
export default function(){
const table = {
key: 'RecordId',
editTable:true ,
footer: "Foots",
cnName: '设备管理_录像记录',
name: 'video_record',
newTabEdit: false,
url: "/video_record/",
sortName: "RecordId",
fixedSearch:false
};
const tableName = table.name;
const tableCNName = table.cnName;
const newTabEdit = false;
const key = table.key;
const editFormFields = {};
const editFormOptions = [];
const searchFormFields = {};
const searchFormOptions = [];
const columns = [{field:'RecordId',title:'录像记录ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'ChannelId',title:'关联通道ID',type:'int',width:110,hidden:true,require:true,align:'left'},
{field:'OwlRecordId',title:'Owl录像记录ID',type:'int',width:110,require:true,align:'left'},
{field:'App',title:'应用名',type:'string',width:110,align:'left'},
{field:'Stream',title:'流ID',type:'string',width:120,align:'left'},
{field:'StartedAt',title:'录像开始时间',type:'datetime',width:110,hidden:true,require:true,align:'left'},
{field:'EndedAt',title:'录像结束时间',type:'datetime',width:110,align:'left'},
{field:'Duration',title:'录像时长(秒)',type:'decimal',width:110,align:'left'},
{field:'FilePath',title:'文件路径',type:'string',width:150,align:'left'},
{field:'FileSize',title:'文件大小(字节)',type:'bigint',width:110,align:'left'},
{field:'CreateDate',title:'创建时间',type:'datetime',width:110,align:'left'}];
const detail ={columns:[]};
const details = [];
return {
table,
key,
tableName,
tableCNName,
newTabEdit,
editFormFields,
editFormOptions,
searchFormFields,
searchFormOptions,
columns,
detail,
details
};
}