This commit is contained in:
仲么了
2024-01-09 13:49:21 +08:00
parent 1d4bc5d442
commit 300d34c1bf
15 changed files with 655 additions and 224 deletions

View File

@@ -15,3 +15,11 @@ export function getAreaList() {
method: 'POST' method: 'POST'
}) })
} }
// 设备列表
export function getDeviceTree() {
return createAxios({
url: '/cs-device-boot/csLedger/deviceTree',
method: 'POST'
})
}

View File

@@ -0,0 +1,17 @@
import createAxios from '@/utils/request'
// 装置基础数据和模板数据
export function getDeviceData(deviceId: string, type: string, lineId = '') {
let form = new FormData()
form.append('deviceId', deviceId)
form.append('lineId', lineId)
form.append('type', type)
return createAxios({
url: '/cs-device-boot/EquipmentDelivery/deviceData',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}

View File

@@ -0,0 +1,15 @@
import createAxios from '@/utils/request'
// 根据数据集获取指标数据
export function getTargetById(id: string) {
let form = new FormData()
form.append('id', id)
return createAxios({
url: '/cs-device-boot/csDataArray/getTargetById',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}

View File

@@ -0,0 +1,15 @@
import createAxios from '@/utils/request'
// 查询分组
export function getGroup(dataSet: string) {
let form = new FormData()
form.append('dataSet', dataSet)
return createAxios({
url: '/cs-device-boot/csGroup/getGroup',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}

View File

@@ -0,0 +1,9 @@
import createAxios from '@/utils/request'
// 设备列表
export function getDeviceTree() {
return createAxios({
url: '/cs-device-boot/csLedger/deviceTree',
method: 'POST'
})
}

View File

@@ -0,0 +1,42 @@
import createAxios from '@/utils/request'
// 字典树接口
export function queryByCode(code: string) {
let form = new FormData()
form.append('code', code)
return createAxios({
url: '/system-boot/dictTree/queryByCode',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}
// 字典树接口通过code
export function queryCsDictTree(pid: string) {
let form = new FormData()
form.append('pid', pid)
return createAxios({
url: '/system-boot/dictTree/query',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}
// 字典树接口通过id
export function queryByid(id: string) {
let form = new FormData()
form.append('id', id)
return createAxios({
url: '/system-boot/dictTree/queryByid',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}

View File

@@ -0,0 +1,35 @@
<template>
<Tree :data="tree" />
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import Tree from './index.vue'
import { getDeviceTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config'
defineOptions({
name: 'govern/deviceTree'
})
const config = useConfig()
const tree = ref()
getDeviceTree().then(res => {
let arr: any[] = []
res.data.forEach(item => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach(item2 => {
item2.icon = 'el-icon-List'
item.color = config.getColorVal('elementUiPrimary')
item2.children.forEach(item3 => {
item3.icon = 'el-icon-Platform'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
arr.push(item3)
})
})
})
tree.value = res.data
})
</script>

View File

@@ -0,0 +1,67 @@
<template>
<div class="cn-tree">
<el-input v-model="filterText" placeholder="请输入内容" clearable style="margin-bottom: 10px">
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input>
<el-tree
style="flex: 1"
ref="treeRef"
:props="defaultProps"
v-bind="$attrs"
highlight-current
default-expand-all
:filter-node-method="filterNode"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }" v-if="data.icon" />
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</template>
<script lang="ts" setup>
import { ref, watch } from 'vue'
defineOptions({
name: 'govern/tree'
})
const filterText = ref('')
const treeRef = ref()
const defaultProps = {
label: 'name',
value: 'id'
}
watch(filterText, val => {
treeRef.value!.filter(val)
})
const filterNode = (value: string, data: any) => {
if (!value) return true
return data.name.includes(value)
}
</script>
<style lang="scss" scoped>
.cn-tree {
flex-shrink: 0;
display: flex;
flex-direction: column;
box-sizing: border-box;
padding: 10px;
height: 100%;
width: 280px;
:deep(.el-tree) {
background: #efeff0;
}
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7);
}
}
.custom-tree-node {
display: flex;
align-items: center;
}
</style>

View File

@@ -58,219 +58,219 @@ const init = async () => {
* 后台初始化请求,获取站点配置,动态路由等信息 * 后台初始化请求,获取站点配置,动态路由等信息
*/ */
getRouteMenu().then((res: any) => { getRouteMenu().then((res: any) => {
// const arr = [ const arr = [
// { {
// id: 1, id: 1,
// pid: 0, pid: 0,
// type: 'menu', type: 'menu',
// title: '控制台', title: '设备管理',
// name: 'dashboard', name: 'dashboard',
// path: 'dashboard', path: 'dashboard',
// icon: 'fa fa-dashboard', icon: 'fa fa-dashboard',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/dashboard/index.vue', component: '/src/views/govern/device/manage.vue',
// keepalive: 'dashboard', keepalive: 'dashboard',
// extend: 'none', extend: 'none',
// children: [] children: []
// }, },
// { {
// id: 3, id: 3,
// pid: 0, pid: 0,
// type: 'menu', type: 'menu',
// title: '审计管理', title: '审计管理',
// name: 'test', name: 'test',
// path: 'test', path: 'test',
// icon: 'el-icon-List', icon: 'el-icon-List',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/dashboard/test.vue', component: '/src/views/dashboard/test.vue',
// keepalive: 'test', keepalive: 'test',
// extend: 'none', extend: 'none',
// children: [ children: [
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '审计列表', title: '审计列表',
// name: 'comptroller/list', name: 'comptroller/list',
// path: 'comptroller/list', path: 'comptroller/list',
// icon: 'el-icon-List', icon: 'el-icon-List',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/comptroller/list.vue', component: '/src/views/comptroller/list.vue',
// keepalive: 'auth/role', keepalive: 'auth/role',
// extend: 'none', extend: 'none',
// children: [] children: []
// } }
// ] ]
// }, },
// { {
// id: 3, id: 3,
// pid: 0, pid: 0,
// type: 'menu_dir', type: 'menu_dir',
// title: '电压暂降', title: '电压暂降',
// name: 'voltage/sags', name: 'voltage/sags',
// path: 'voltage/sags', path: 'voltage/sags',
// icon: 'el-icon-BellFilled', icon: 'el-icon-BellFilled',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// extend: 'none', extend: 'none',
// children: [ children: [
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu_dir', type: 'menu_dir',
// title: '运行管理', title: '运行管理',
// name: 'voltage/sags/operationsManagement', name: 'voltage/sags/operationsManagement',
// path: 'voltage/sags/operationsManagement', path: 'voltage/sags/operationsManagement',
// icon: 'fa-solid fa-bars-progress', icon: 'fa-solid fa-bars-progress',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// extend: 'none', extend: 'none',
// children: [ children: [
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '终端运行管理', title: '终端运行管理',
// name: 'voltage/sags/operationsManagement/index', name: 'voltage/sags/operationsManagement/index',
// path: 'voltage/sags/operationsManagement/index', path: 'voltage/sags/operationsManagement/index',
// icon: 'fa-solid fa-recycle', icon: 'fa-solid fa-recycle',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/voltage/sags/operationsManagement/index.vue', component: '/src/views/voltage/sags/operationsManagement/index.vue',
// keepalive: 'voltage/sags/operationsManagement/index', keepalive: 'voltage/sags/operationsManagement/index',
// extend: 'none', extend: 'none',
// children: [] children: []
// }, },
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '终端运行统计', title: '终端运行统计',
// name: 'voltage/sags/operationsManagement/statistics', name: 'voltage/sags/operationsManagement/statistics',
// path: 'voltage/sags/operationsManagement/statistics', path: 'voltage/sags/operationsManagement/statistics',
// icon: 'fa-solid fa-chart-column', icon: 'fa-solid fa-chart-column',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/voltage/sags/operationsManagement/statistics.vue', component: '/src/views/voltage/sags/operationsManagement/statistics.vue',
// keepalive: 'voltage/sags/operationsManagement/statistics', keepalive: 'voltage/sags/operationsManagement/statistics',
// extend: 'none', extend: 'none',
// children: [] children: []
// }, },
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '监测点台账信息', title: '监测点台账信息',
// name: 'voltage/sags/operationsManagement/point', name: 'voltage/sags/operationsManagement/point',
// path: 'voltage/sags/operationsManagement/point', path: 'voltage/sags/operationsManagement/point',
// icon: 'fa-brands fa-square-pinterest', icon: 'fa-brands fa-square-pinterest',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/voltage/sags/operationsManagement/point.vue', component: '/src/views/voltage/sags/operationsManagement/point.vue',
// keepalive: 'voltage/sags/operationsManagement/point', keepalive: 'voltage/sags/operationsManagement/point',
// extend: 'none', extend: 'none',
// children: [] children: []
// } }
// ] ]
// }, },
// { {
// id: 2, id: 2,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '区域', title: '区域',
// name: 'Event-boot/Region/distribution', name: 'Event-boot/Region/distribution',
// path: 'Event-boot/Region/distribution', path: 'Event-boot/Region/distribution',
// icon: 'el-icon-Management', icon: 'el-icon-Management',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/Event-boot/Region/distribution.vue', component: '/src/views/Event-boot/Region/distribution.vue',
// keepalive: 'Event-boot/Region/distribution', keepalive: 'Event-boot/Region/distribution',
// extend: 'none', extend: 'none',
// children: [ children: [
// { {
// id: 2, id: 2,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '区域概览', title: '区域概览',
// name: 'Region/overview', name: 'Region/overview',
// path: 'Region/overview', path: 'Region/overview',
// icon: 'el-icon-Promotion', icon: 'el-icon-Promotion',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/dashboard/index.vue', component: '/src/views/dashboard/index.vue',
// keepalive: 'Region/overview', keepalive: 'Region/overview',
// extend: 'none', extend: 'none',
// children: [] children: []
// }, },
// { {
// id: 1, id: 1,
// pid: 3, pid: 3,
// type: 'menu', type: 'menu',
// title: '监测网分布', title: '监测网分布',
// name: 'Region/distribution', name: 'Region/distribution',
// path: 'Region/distribution', path: 'Region/distribution',
// icon: 'el-icon-Share', icon: 'el-icon-Share',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/Event-boot/Region/distribution.vue', component: '/src/views/Event-boot/Region/distribution.vue',
// keepalive: 'Region/distribution', keepalive: 'Region/distribution',
// extend: 'none', extend: 'none',
// children: [] children: []
// } }
// ] ]
// } }
// ] ]
// }, },
// { {
// id: 2, id: 2,
// pid: 0, pid: 0,
// type: 'menu_dir', type: 'menu_dir',
// title: '权限管理', title: '权限管理',
// name: 'auth', name: 'auth',
// path: 'auth', path: 'auth',
// icon: 'fa-solid fa-layer-group', icon: 'fa-solid fa-layer-group',
// menu_type: null, menu_type: null,
// url: '', url: '',
// component: '', component: '',
// keepalive: 0, keepalive: 0,
// extend: 'none', extend: 'none',
// children: [ children: [
// { {
// id: 3, id: 3,
// pid: 2, pid: 2,
// type: 'menu', type: 'menu',
// title: '角色管理', title: '角色管理',
// name: 'auth/role', name: 'auth/role',
// path: 'auth/role', path: 'auth/role',
// icon: 'el-icon-Avatar', icon: 'el-icon-Avatar',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/auth/role/index.vue', component: '/src/views/auth/role/index.vue',
// keepalive: 'auth/role', keepalive: 'auth/role',
// extend: 'none', extend: 'none',
// children: [] children: []
// }, },
// { {
// id: 13, id: 13,
// pid: 2, pid: 2,
// type: 'menu', type: 'menu',
// title: '菜单规则管理', title: '菜单规则管理',
// name: 'auth/menu', name: 'auth/menu',
// path: 'auth/menu', path: 'auth/menu',
// icon: 'el-icon-Menu', icon: 'el-icon-Menu',
// menu_type: 'tab', menu_type: 'tab',
// url: '', url: '',
// component: '/src/views/auth/menu/index.vue', component: '/src/views/auth/menu/index.vue',
// keepalive: 'auth/menu', keepalive: 'auth/menu',
// extend: 'none', extend: 'none',
// children: [] children: []
// } }
// ] ]
// } }
// ] ]
const handlerMenu = (data: any) => { const handlerMenu = (data: any) => {
data.forEach((item: any) => { data.forEach((item: any) => {
@@ -287,8 +287,8 @@ const init = async () => {
} }
handlerMenu(res.data) handlerMenu(res.data)
// handleAdminRoute(arr) // handleAdminRoute(arr)
handleAdminRoute(res.data) // handleAdminRoute(res.data)
// handleAdminRoute([...arr, ...res.data]) handleAdminRoute([...arr, ...res.data])
// 预跳转到上次路径 // 预跳转到上次路径
if (route.params.to) { if (route.params.to) {

View File

@@ -108,30 +108,30 @@ body,
/* 表格-e */ /* 表格-e */
/* 新增/编辑表单-s */ /* 新增/编辑表单-s */
.ba-operate-dialog { .cn-operate-dialog {
overflow: hidden; overflow: hidden;
border-radius: var(--el-border-radius-base); border-radius: var(--el-border-radius-base);
} }
.ba-operate-dialog .el-dialog__header { .cn-operate-dialog .el-dialog__header {
padding-bottom: 16px; padding-bottom: 16px;
border-bottom: 1px solid var(--ba-bg-color); border-bottom: 1px solid var(--ba-bg-color);
} }
.ba-operate-dialog .el-dialog__body { .cn-operate-dialog .el-dialog__body {
height: 60vh; height: 60vh;
padding-top: 20px; padding-top: 20px;
padding-bottom: 52px; padding-bottom: 52px;
} }
.ba-operate-dialog .el-dialog__body .el-scrollbar { .cn-operate-dialog .el-dialog__body .el-scrollbar {
padding-right: 60px; padding-right: 60px;
} }
.ba-operate-dialog .el-dialog__footer { .cn-operate-dialog .el-dialog__footer {
padding: 10px var(--el-dialog-padding-primary); padding: 10px var(--el-dialog-padding-primary);
box-shadow: var(--el-box-shadow); box-shadow: var(--el-box-shadow);
position: absolute; position: absolute;
width: 100%; width: 100%;
bottom: 0; bottom: 0;
} }
.ba-operate-dialog .el-form--inline { .cn-operate-dialog .el-form--inline {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(600px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(600px, 1fr));
} }
@@ -228,7 +228,7 @@ body,
} }
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 1024px) {
.ba-operate-dialog { .cn-operate-dialog {
width: 96%; width: 96%;
} }
} }
@@ -238,3 +238,4 @@ body,
} }
} }
/* 自适应-e */ /* 自适应-e */

View File

@@ -28,3 +28,38 @@
} }
} }
} }
// mt0,mr0,mb0,ml0 --> mt100,mr100,mb100,ml100
@for $i from 0 through 100 {
.mt#{$i} {
margin-top: #{$i}px !important;
}
.mr#{$i} {
margin-right: #{$i}px !important;
}
.mb#{$i} {
margin-bottom: #{$i}px !important;
}
.ml#{$i} {
margin-left: #{$i}px !important;
}
.pt#{$i} {
padding-top: #{$i}px !important;
}
.pr#{$i} {
padding-right: #{$i}px !important;
}
.pb#{$i} {
padding-bottom: #{$i}px !important;
}
.pl#{$i} {
padding-left: #{$i}px !important;
}
}

View File

@@ -1,5 +1,5 @@
<template> <template>
<el-dialog class='ba-operate-dialog' v-model='dialogVisible' :title='title'> <el-dialog class='cn-operate-dialog' v-model='dialogVisible' :title='title'>
<el-scrollbar> <el-scrollbar>
<el-form :inline='false' :model='form' label-width='120px'> <el-form :inline='false' :model='form' label-width='120px'>
<el-form-item label='上级菜单'> <el-form-item label='上级菜单'>

View File

@@ -1,5 +1,5 @@
<template> <template>
<el-dialog class="ba-operate-dialog" v-model="dialogVisible" :title="title"> <el-dialog class="cn-operate-dialog" v-model="dialogVisible" :title="title">
<el-scrollbar> <el-scrollbar>
<el-form :inline="false" :model="form" label-width="120px"> <el-form :inline="false" :model="form" label-width="120px">
<el-form-item label="上级菜单"> <el-form-item label="上级菜单">

View File

@@ -0,0 +1,172 @@
<template>
<div class="default-main manage" :style="{ height: pageHeight.height }">
<DeviceTree @node-click="nodeClick"></DeviceTree>
<div class="manage-right" v-if="deviceData" v-loading="loading">
<el-descriptions title="设备基本信息" class="mb10" :column="3" border>
<template #extra>
<el-button
type="primary"
icon="el-icon-Share"
@click="openGroup"
size="small"
:loading="getGroupLoading"
>
设备模版分组
</el-button>
</template>
<el-descriptions-item label="名称">
{{ deviceData.name }}
</el-descriptions-item>
<el-descriptions-item label="类型">
{{ echoName(deviceData.devType, devTypeOptions) }}
</el-descriptions-item>
<el-descriptions-item label="接入方式">
{{ deviceData.devAccessMethod }}
</el-descriptions-item>
<el-descriptions-item label="识别码">
{{ deviceData.ndid }}
</el-descriptions-item>
<el-descriptions-item label="型号">
{{ echoName(deviceData.devModel, devModelOptions) }}
</el-descriptions-item>
<el-descriptions-item label="接入时间">
{{ deviceData.time }}
</el-descriptions-item>
</el-descriptions>
<el-tabs v-model="dataSet" type="card" class="device-manage-box-card" @tab-click="handleClick">
<el-tab-pane
lazy
:label="item.name"
:name="item.id"
v-for="item in deviceData.dataSetList"
:key="item.id"
></el-tab-pane>
<div :style="{ height: tableHeight }">
<vxe-table v-bind="defaultAttribute" :data="tableData" height="auto" style="width: 100%">
<vxe-column type="seq" title="序号" width="80"></vxe-column>
<vxe-column field="name" title="数据名称"></vxe-column>
<vxe-column field="phasic" title="相别"></vxe-column>
<vxe-column field="type" title="数据类型"></vxe-column>
<vxe-column field="unit" title="单位"></vxe-column>
<vxe-column field="startTimes" title="开始次数"></vxe-column>
<vxe-column field="endTimes" title="结束次数"></vxe-column>
</vxe-table>
</div>
</el-tabs>
</div>
<MangePopup ref="mangePopup" />
</div>
</template>
<script setup lang="ts">
defineOptions({
name: 'govern/device/manage'
})
import MangePopup from './managePopup.vue'
import DeviceTree from '@/components/tree/deviceTree.vue'
import { mainHeight } from '@/utils/layout'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { getDeviceData } from '@/api/cs-device-boot/EquipmentDelivery'
import { getTargetById } from '@/api/cs-device-boot/csDataArray'
import { getGroup } from '@/api/cs-device-boot/csGroup'
import { ref, reactive } from 'vue'
import { ElMessage } from 'element-plus'
import { defaultAttribute } from '@/components/table/defaultAttribute'
const pageHeight = mainHeight(20)
const loading = ref(false)
const selectAll = ref(false)
const dialogFormVisible = ref(false)
const getGroupLoading = ref(false)
const newGroupVisible = ref(false)
const deviceData = ref<any>(null)
const dataSet = ref('')
const devTypeOptions = ref([])
const devModelOptions = ref([])
const tableData = ref([])
const tableHeight = mainHeight(230).height
const mangePopup = ref()
const nodeClick = (e: anyObj) => {
if (e.level == 2) {
loading.value = true
getDeviceData(e.id, 'rt').then((res: any) => {
deviceData.value = res.data
loading.value = false
if (res.data.dataSetList.length === 0) {
dataSet.value = ''
tableData.value = []
} else {
dataSet.value = res.data.dataSetList[0].id
handleClick()
}
})
}
}
const handleClick = () => {
tableData.value = []
getTargetById(dataSet.value).then(res => {
tableData.value = res.data
})
}
queryByCode('Device_Type').then(res => {
queryCsDictTree(res.data.id).then(res => {
devTypeOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
queryByid(res.data.id).then(res => {
devModelOptions.value = res.data.map((item: any) => {
return {
value: item.id,
label: item.name,
...item
}
})
})
})
const echoName = (value: any, arr: any[]) => {
return arr.find(item => item.value == value).label
}
const openGroup = () => {
if (!dataSet.value) {
return ElMessage.warning('暂无数据')
}
getGroupLoading.value = true
getGroup(dataSet.value).then((res: any) => {
const call = (data: any[]) => {
data.forEach(item => {
item.label = item.name
item.isShow = item.isShow == 1
if (item.children && item.children.length > 0) {
call(item.children)
}
})
}
call(res.data)
getGroupLoading.value = false
mangePopup.value.open(res.data, dataSet.value)
})
}
</script>
<style lang="scss">
.manage {
display: flex;
&-right {
overflow: hidden;
flex: 1;
padding: 10px 10px 10px 0;
.el-descriptions__header {
height: 36px;
margin-bottom: 7px;
display: flex;
align-items: center;
}
}
}
</style>

View File

@@ -0,0 +1,15 @@
<template>
<el-dialog class="cn-operate-dialog" v-model="dialogVisible" title="设备模版分组">111</el-dialog>
</template>
<script lang="ts" setup>
import { ref, inject } from 'vue'
const dialogVisible = ref(false)
const popupData = ref<any[]>([])
const open = (data: any[]) => {
dialogVisible.value = true
popupData.value = data
}
defineExpose({ open })
</script>