|
|
|
|
@ -65,16 +65,16 @@
|
|
|
|
|
:key="index"
|
|
|
|
|
class="w-full flex items-center gap-8px"
|
|
|
|
|
>
|
|
|
|
|
<el-tree-select
|
|
|
|
|
v-model="rule.pointValue"
|
|
|
|
|
:data="equipmentTree"
|
|
|
|
|
:props="treeSelectProps"
|
|
|
|
|
<el-cascader
|
|
|
|
|
v-model='rule.pointValue'
|
|
|
|
|
:options='devicePointOptions'
|
|
|
|
|
:props='devicePointCascaderProps'
|
|
|
|
|
filterable
|
|
|
|
|
clearable
|
|
|
|
|
class="!w-full"
|
|
|
|
|
:placeholder="t('EnergyManagement.EnergyDevice.dialogRulesPointPlaceholder')"
|
|
|
|
|
:loading="analysisLoading"
|
|
|
|
|
@change="(val) => handlePointSelected(index, val)"
|
|
|
|
|
:show-all-levels='false'
|
|
|
|
|
@change='(val) => handlePointSelected(index, val)'
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<template v-if="index < formData.operationRulesVOList.length - 1">
|
|
|
|
|
@ -132,6 +132,7 @@
|
|
|
|
|
import { EnergyDeviceApi, EnergyDeviceVO } from '@/api/mes/energydevice'
|
|
|
|
|
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
|
|
|
|
|
import { OrganizationApi } from '@/api/mes/organization'
|
|
|
|
|
import { DeviceApi } from '@/api/iot/device'
|
|
|
|
|
import { Remove } from '@element-plus/icons-vue'
|
|
|
|
|
|
|
|
|
|
/** 能源设备 表单 */
|
|
|
|
|
@ -205,27 +206,11 @@ const formRef = ref() // 表单 Ref
|
|
|
|
|
|
|
|
|
|
const analysisLoading = ref(false)
|
|
|
|
|
|
|
|
|
|
type AnalysisParameter = {
|
|
|
|
|
id: number | string
|
|
|
|
|
name: string
|
|
|
|
|
code?: string
|
|
|
|
|
type?: string | null
|
|
|
|
|
dataType?: string | null
|
|
|
|
|
unit?: string | null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AnalysisEquipment = {
|
|
|
|
|
id: number | string
|
|
|
|
|
name: string
|
|
|
|
|
parameters?: AnalysisParameter[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AnalysisOrgNode = {
|
|
|
|
|
id: number | string
|
|
|
|
|
name: string
|
|
|
|
|
orgClass?: string
|
|
|
|
|
parentId?: number | string | null
|
|
|
|
|
equipments?: AnalysisEquipment[]
|
|
|
|
|
children?: AnalysisOrgNode[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -237,16 +222,18 @@ type OrgSelectNode = {
|
|
|
|
|
children?: OrgSelectNode[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type EquipmentTreeNode = {
|
|
|
|
|
id: string
|
|
|
|
|
name: string
|
|
|
|
|
disabled?: boolean
|
|
|
|
|
type DevicePointOption = {
|
|
|
|
|
value: number | string
|
|
|
|
|
label: string
|
|
|
|
|
leaf?: boolean
|
|
|
|
|
dataType?: string | null
|
|
|
|
|
children?: EquipmentTreeNode[]
|
|
|
|
|
children?: DevicePointOption[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const analysisTree = ref<AnalysisOrgNode[]>([])
|
|
|
|
|
const orgSelectTree = ref<OrgSelectNode[]>([])
|
|
|
|
|
const devicePointOptions = ref<DevicePointOption[]>([])
|
|
|
|
|
const devicePointCache = new Map<string, DevicePointOption[]>()
|
|
|
|
|
|
|
|
|
|
const orgTreeSelectProps = {
|
|
|
|
|
label: 'name',
|
|
|
|
|
@ -254,11 +241,13 @@ const orgTreeSelectProps = {
|
|
|
|
|
value: 'id'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const treeSelectProps = {
|
|
|
|
|
label: 'name',
|
|
|
|
|
children: 'children',
|
|
|
|
|
disabled: 'disabled',
|
|
|
|
|
value: 'id'
|
|
|
|
|
const devicePointCascaderProps = {
|
|
|
|
|
value: 'value', label: 'label', children: 'children', leaf: 'leaf', lazy: true,
|
|
|
|
|
lazyLoad: async (node: any, resolve: (nodes: DevicePointOption[]) => void) => {
|
|
|
|
|
if (node.level === 0) { resolve(devicePointOptions.value); return }
|
|
|
|
|
if (node.level === 1) { resolve(await loadDevicePoints(node.value)); return }
|
|
|
|
|
resolve([])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const operatorOptions = ['+', '-', '*', '/']
|
|
|
|
|
@ -279,15 +268,12 @@ const findOrgNode = (nodes: OrgSelectNode[], id: any): OrgSelectNode | undefined
|
|
|
|
|
return undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const normalizeAnalysisId = (value: any) => String(value ?? '')
|
|
|
|
|
|
|
|
|
|
const normalizeAnalysisTree = (nodes: any[] = []): AnalysisOrgNode[] => {
|
|
|
|
|
return nodes.map((node) => ({
|
|
|
|
|
id: node?.id,
|
|
|
|
|
name: String(node?.name ?? ''),
|
|
|
|
|
orgClass: node?.orgClass ? String(node.orgClass) : undefined,
|
|
|
|
|
parentId: node?.parentId ?? undefined,
|
|
|
|
|
equipments: Array.isArray(node?.equipments) ? node.equipments : [],
|
|
|
|
|
children: Array.isArray(node?.children) ? normalizeAnalysisTree(node.children) : undefined
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
@ -310,76 +296,8 @@ const extractAnalysisOrgs = (res: any): AnalysisOrgNode[] => {
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const findAnalysisNode = (nodes: AnalysisOrgNode[], id: any): AnalysisOrgNode | undefined => {
|
|
|
|
|
for (const node of nodes) {
|
|
|
|
|
if (isSameId(node.id, id)) return node
|
|
|
|
|
const children = Array.isArray(node.children) ? node.children : []
|
|
|
|
|
if (children.length) {
|
|
|
|
|
const found = findAnalysisNode(children, id)
|
|
|
|
|
if (found) return found
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const collectEquipmentTree = (nodes: AnalysisOrgNode[] = []): EquipmentTreeNode[] => {
|
|
|
|
|
const equipmentNodes: EquipmentTreeNode[] = []
|
|
|
|
|
|
|
|
|
|
const walk = (node: AnalysisOrgNode) => {
|
|
|
|
|
const equipments = Array.isArray(node.equipments) ? node.equipments : []
|
|
|
|
|
equipments.forEach((equipment) => {
|
|
|
|
|
const deviceId = normalizeAnalysisId(equipment?.id)
|
|
|
|
|
if (!deviceId) return
|
|
|
|
|
const parameterNodes = (Array.isArray(equipment.parameters) ? equipment.parameters : [])
|
|
|
|
|
.map((parameter) => {
|
|
|
|
|
const pointId = normalizeAnalysisId(parameter?.id)
|
|
|
|
|
if (!pointId) return undefined
|
|
|
|
|
return {
|
|
|
|
|
id: deviceId + ':' + pointId,
|
|
|
|
|
name: String(parameter?.name ?? parameter?.code ?? pointId),
|
|
|
|
|
dataType: parameter?.dataType ?? parameter?.type ?? undefined
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.filter(Boolean) as EquipmentTreeNode[]
|
|
|
|
|
|
|
|
|
|
if (parameterNodes.length) {
|
|
|
|
|
equipmentNodes.push({
|
|
|
|
|
id: 'device:' + deviceId,
|
|
|
|
|
name: String(equipment?.name ?? deviceId),
|
|
|
|
|
disabled: true,
|
|
|
|
|
children: parameterNodes
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const children = Array.isArray(node.children) ? node.children : []
|
|
|
|
|
children.forEach(walk)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nodes.forEach(walk)
|
|
|
|
|
return equipmentNodes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const equipmentTree = computed(() => {
|
|
|
|
|
if (!formData.value.orgId) return []
|
|
|
|
|
const selectedOrg = findAnalysisNode(analysisTree.value, formData.value.orgId)
|
|
|
|
|
return selectedOrg ? collectEquipmentTree([selectedOrg]) : []
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const findPointDataType = (deviceId: any, pointId: any): string | undefined => {
|
|
|
|
|
const deviceKey = normalizeAnalysisId(deviceId)
|
|
|
|
|
const pointKey = normalizeAnalysisId(pointId)
|
|
|
|
|
if (!deviceKey || !pointKey) return undefined
|
|
|
|
|
const key = deviceKey + ':' + pointKey
|
|
|
|
|
for (const group of collectEquipmentTree(analysisTree.value)) {
|
|
|
|
|
const children = Array.isArray(group.children) ? group.children : []
|
|
|
|
|
for (const child of children) {
|
|
|
|
|
if (String(child.id ?? '') === key) {
|
|
|
|
|
return child.dataType as string | undefined
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return undefined
|
|
|
|
|
return devicePointCache.get(String(deviceId))?.find((point) => isSameId(point.value, pointId))?.dataType as string | undefined
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const open = async (type: string, id?: number) => {
|
|
|
|
|
@ -388,7 +306,7 @@ const open = async (type: string, id?: number) => {
|
|
|
|
|
formType.value = type
|
|
|
|
|
resetForm()
|
|
|
|
|
|
|
|
|
|
await loadAnalysis()
|
|
|
|
|
await Promise.all([loadAnalysis(), loadDeviceOptions()])
|
|
|
|
|
// 修改时,设置数据
|
|
|
|
|
if (id) {
|
|
|
|
|
formLoading.value = true
|
|
|
|
|
@ -399,7 +317,7 @@ const open = async (type: string, id?: number) => {
|
|
|
|
|
{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
hydratePointValues()
|
|
|
|
|
await hydratePointValues()
|
|
|
|
|
} finally {
|
|
|
|
|
formLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
@ -488,6 +406,24 @@ const loadAnalysis = async () => {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loadDeviceOptions = async () => {
|
|
|
|
|
if (devicePointOptions.value.length) return
|
|
|
|
|
const devices = await DeviceApi.getDeviceList()
|
|
|
|
|
devicePointOptions.value = (devices ?? []).map((device: any) => ({ value: device.id, label: String(device.deviceName ?? device.deviceCode ?? device.id) }))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const loadDevicePoints = async (deviceId: number | string): Promise<DevicePointOption[]> => {
|
|
|
|
|
const cacheKey = String(deviceId)
|
|
|
|
|
const cached = devicePointCache.get(cacheKey)
|
|
|
|
|
if (cached) return cached
|
|
|
|
|
const data = await DeviceApi.getDeviceAttributePage({ pageNo: 1, pageSize: 100, deviceId })
|
|
|
|
|
const points = (data?.list ?? []).map((point: any) => ({ value: point.id, label: String(point.attributeName ?? point.attributeCode ?? point.id), leaf: true, dataType: point.dataType ?? point.type ?? undefined }))
|
|
|
|
|
devicePointCache.set(cacheKey, points)
|
|
|
|
|
const device = devicePointOptions.value.find((item) => isSameId(item.value, deviceId))
|
|
|
|
|
if (device) device.children = points
|
|
|
|
|
return points
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDeviceTypeChange = () => {
|
|
|
|
|
formData.value.unitName = typeList.value.find(
|
|
|
|
|
(item) => item.id === formData.value.deviceTypeId
|
|
|
|
|
@ -508,14 +444,12 @@ const handleOrgChange = () => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handlePointSelected = (index: number, val: any) => {
|
|
|
|
|
if (!val || typeof val !== 'string' || !val.includes(':')) {
|
|
|
|
|
if (!Array.isArray(val) || val.length !== 2) {
|
|
|
|
|
formData.value.operationRulesVOList[index].deviceId = undefined
|
|
|
|
|
formData.value.operationRulesVOList[index].pointId = undefined
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const [deviceIdStr, pointIdStr] = val.split(':')
|
|
|
|
|
const deviceId = deviceIdStr || undefined
|
|
|
|
|
const pointId = pointIdStr || undefined
|
|
|
|
|
const [deviceId, pointId] = val
|
|
|
|
|
formData.value.operationRulesVOList[index].deviceId = deviceId
|
|
|
|
|
formData.value.operationRulesVOList[index].pointId = pointId
|
|
|
|
|
}
|
|
|
|
|
@ -550,16 +484,15 @@ const buildOperationRulesPayload = () => {
|
|
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hydratePointValues = () => {
|
|
|
|
|
const hydratePointValues = async () => {
|
|
|
|
|
const list = (formData.value as any).operationRulesVOList as any[]
|
|
|
|
|
if (!Array.isArray(list)) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
list.forEach((r) => {
|
|
|
|
|
if (r?.deviceId && r?.pointId) {
|
|
|
|
|
r.pointValue = `${r.deviceId}:${r.pointId}`
|
|
|
|
|
if (!Array.isArray(list)) return
|
|
|
|
|
await Promise.all(list.map(async (rule) => {
|
|
|
|
|
if (rule?.deviceId && rule?.pointId) {
|
|
|
|
|
await loadDevicePoints(rule.deviceId)
|
|
|
|
|
rule.pointValue = [rule.deviceId, rule.pointId]
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const validateRules = (callback: any) => {
|
|
|
|
|
|