|
|
|
|
@ -23,7 +23,10 @@
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item :label="t('EnergyManagement.EnergyDevice.dialogEnergyTypeLabel')" prop="deviceTypeId">
|
|
|
|
|
<el-form-item
|
|
|
|
|
:label="t('EnergyManagement.EnergyDevice.dialogEnergyTypeLabel')"
|
|
|
|
|
prop="deviceTypeId"
|
|
|
|
|
>
|
|
|
|
|
<el-select
|
|
|
|
|
v-model="formData.deviceTypeId"
|
|
|
|
|
@change="handleDeviceTypeChange"
|
|
|
|
|
@ -52,11 +55,16 @@
|
|
|
|
|
/>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
<el-form-item :label="t('EnergyManagement.EnergyDevice.dialogRulesLabel')" prop="operationRulesVOList">
|
|
|
|
|
<el-form-item
|
|
|
|
|
:label="t('EnergyManagement.EnergyDevice.dialogRulesLabel')"
|
|
|
|
|
prop="operationRulesVOList"
|
|
|
|
|
>
|
|
|
|
|
<div class="w-full flex flex-col gap-8px">
|
|
|
|
|
<div
|
|
|
|
|
v-for="(rule, index) in formData.operationRulesVOList" :key="index"
|
|
|
|
|
class="w-full flex items-center gap-8px">
|
|
|
|
|
v-for="(rule, index) in formData.operationRulesVOList"
|
|
|
|
|
:key="index"
|
|
|
|
|
class="w-full flex items-center gap-8px"
|
|
|
|
|
>
|
|
|
|
|
<el-tree-select
|
|
|
|
|
v-model="rule.pointValue"
|
|
|
|
|
:data="equipmentTree"
|
|
|
|
|
@ -84,7 +92,12 @@ v-for="(rule, index) in formData.operationRulesVOList" :key="index"
|
|
|
|
|
<el-button link type="primary" @click="addRule">
|
|
|
|
|
<Icon icon="ep:plus" />
|
|
|
|
|
</el-button>
|
|
|
|
|
<el-button link type="danger" :disabled="formData.operationRulesVOList.length <= 1" @click="removeRule">
|
|
|
|
|
<el-button
|
|
|
|
|
link
|
|
|
|
|
type="danger"
|
|
|
|
|
:disabled="formData.operationRulesVOList.length <= 1"
|
|
|
|
|
@click="removeRule"
|
|
|
|
|
>
|
|
|
|
|
<el-icon>
|
|
|
|
|
<Remove />
|
|
|
|
|
</el-icon>
|
|
|
|
|
@ -92,7 +105,9 @@ v-for="(rule, index) in formData.operationRulesVOList" :key="index"
|
|
|
|
|
</div>
|
|
|
|
|
</template>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="text-12px text-[#909399] leading-20px">按“计算规则”添加顺序从上到下依次计算,不按乘除优先。</div>
|
|
|
|
|
<div class="text-12px text-[#909399] leading-20px"
|
|
|
|
|
>按“计算规则”添加顺序从上到下依次计算,不按乘除优先。</div
|
|
|
|
|
>
|
|
|
|
|
</div>
|
|
|
|
|
</el-form-item>
|
|
|
|
|
|
|
|
|
|
@ -115,11 +130,10 @@ v-for="(rule, index) in formData.operationRulesVOList" :key="index"
|
|
|
|
|
</template>
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import { EnergyDeviceApi, EnergyDeviceVO } from '@/api/mes/energydevice'
|
|
|
|
|
import { EnergyTypeApi, EnergyTypeVO } from "@/api/mes/energytype";
|
|
|
|
|
import { OrganizationApi, DeviceParameterAnalysisNodeVO } from '@/api/mes/organization'
|
|
|
|
|
import { EnergyTypeApi, EnergyTypeVO } from '@/api/mes/energytype'
|
|
|
|
|
import { DeviceLineApi, DeviceLineTreeVO } from '@/api/mes/deviceline'
|
|
|
|
|
import { DeviceApi } from '@/api/iot/device'
|
|
|
|
|
import { Remove } from '@element-plus/icons-vue'
|
|
|
|
|
import { handleTree } from '@/utils/tree'
|
|
|
|
|
|
|
|
|
|
/** 能源设备 表单 */
|
|
|
|
|
defineOptions({ name: 'EnergyDeviceForm' })
|
|
|
|
|
@ -147,61 +161,53 @@ const formData = ref({
|
|
|
|
|
orgId: undefined,
|
|
|
|
|
orgName: undefined,
|
|
|
|
|
rules: undefined,
|
|
|
|
|
operationRulesVOList: [{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }],
|
|
|
|
|
operationRulesVOList: [
|
|
|
|
|
{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
const formRules = reactive({
|
|
|
|
|
name: [{ required: true, message: t('EnergyManagement.EnergyDevice.validatorNameRequired'), trigger: 'blur' }],
|
|
|
|
|
code: [{ required: true, message: t('EnergyManagement.EnergyDevice.validatorCodeRequired'), trigger: 'blur' }],
|
|
|
|
|
orgId: [{ required: true, message: t('EnergyManagement.EnergyDevice.validatorOrgRequired'), trigger: 'change' }],
|
|
|
|
|
operationRulesVOList: [{ required: true, validator: (_rule, _value, callback) => validateRules(callback), trigger: 'change' }],
|
|
|
|
|
isEnable: [{ required: true, message: t('EnergyManagement.EnergyDevice.validatorIsEnableRequired'), trigger: 'blur' }]
|
|
|
|
|
name: [
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: t('EnergyManagement.EnergyDevice.validatorNameRequired'),
|
|
|
|
|
trigger: 'blur'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
code: [
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: t('EnergyManagement.EnergyDevice.validatorCodeRequired'),
|
|
|
|
|
trigger: 'blur'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
orgId: [
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: t('EnergyManagement.EnergyDevice.validatorOrgRequired'),
|
|
|
|
|
trigger: 'change'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
operationRulesVOList: [
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
validator: (_rule, _value, callback) => validateRules(callback),
|
|
|
|
|
trigger: 'change'
|
|
|
|
|
}
|
|
|
|
|
],
|
|
|
|
|
isEnable: [
|
|
|
|
|
{
|
|
|
|
|
required: true,
|
|
|
|
|
message: t('EnergyManagement.EnergyDevice.validatorIsEnableRequired'),
|
|
|
|
|
trigger: 'blur'
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
const formRef = ref() // 表单 Ref
|
|
|
|
|
|
|
|
|
|
const analysisLoading = ref(false)
|
|
|
|
|
type OrgAnalysisNode = DeviceParameterAnalysisNodeVO & { children?: OrgAnalysisNode[] }
|
|
|
|
|
|
|
|
|
|
const analysisList = ref<OrgAnalysisNode[]>([])
|
|
|
|
|
type OrgSelectNode = DeviceLineTreeVO & { children?: OrgSelectNode[] }
|
|
|
|
|
|
|
|
|
|
const analysisTree = computed(() => {
|
|
|
|
|
const list = analysisList.value ?? []
|
|
|
|
|
if (!list.length) return [] as OrgAnalysisNode[]
|
|
|
|
|
|
|
|
|
|
const hasChildren = list.some((n) => Array.isArray((n as any).children) && (n as any).children.length)
|
|
|
|
|
if (hasChildren) {
|
|
|
|
|
return list.map((n) => ({ ...n })) as OrgAnalysisNode[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const hasParentId = list.some((n) => (n as any).parentId !== undefined && (n as any).parentId !== null)
|
|
|
|
|
if (!hasParentId) {
|
|
|
|
|
return list.map((n) => ({ ...n })) as OrgAnalysisNode[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const cloned = list.map((n) => ({ ...n })) as OrgAnalysisNode[]
|
|
|
|
|
return handleTree(cloned as any[], 'id', 'parentId', 'children') as OrgAnalysisNode[]
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
type OrgSelectNode = {
|
|
|
|
|
id: number | string
|
|
|
|
|
name: string
|
|
|
|
|
children?: OrgSelectNode[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const orgSelectTree = computed(() => {
|
|
|
|
|
const tree = analysisTree.value ?? []
|
|
|
|
|
if (!tree.length) return [] as OrgSelectNode[]
|
|
|
|
|
|
|
|
|
|
const pruneAndAttach = (nodes: OrgAnalysisNode[]): OrgSelectNode[] => {
|
|
|
|
|
const kept: OrgSelectNode[] = []
|
|
|
|
|
nodes.forEach((node) => {
|
|
|
|
|
const childNodes = Array.isArray(node.children) ? pruneAndAttach(node.children) : []
|
|
|
|
|
kept.push({ id: node.id, name: node.name, children: childNodes.length ? childNodes : undefined })
|
|
|
|
|
})
|
|
|
|
|
return kept
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pruneAndAttach(tree)
|
|
|
|
|
})
|
|
|
|
|
const orgSelectTree = ref<OrgSelectNode[]>([])
|
|
|
|
|
|
|
|
|
|
const orgTreeSelectProps = {
|
|
|
|
|
label: 'name',
|
|
|
|
|
@ -222,7 +228,7 @@ const isSameId = (a: any, b: any) => {
|
|
|
|
|
return String(a ?? '') === String(b ?? '')
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const findOrgNode = (nodes: OrgAnalysisNode[], id: any): OrgAnalysisNode | undefined => {
|
|
|
|
|
const findOrgNode = (nodes: OrgSelectNode[], id: any): OrgSelectNode | undefined => {
|
|
|
|
|
for (const node of nodes) {
|
|
|
|
|
if (isSameId(node.id, id)) return node
|
|
|
|
|
const children = Array.isArray(node.children) ? node.children : []
|
|
|
|
|
@ -251,22 +257,39 @@ const loadDevicePointTree = async () => {
|
|
|
|
|
|
|
|
|
|
const deviceGroups = new Map<string, { deviceId: string; deviceName: string; points: any[] }>()
|
|
|
|
|
|
|
|
|
|
const pushPoint = (deviceId: any, deviceName: any, pointId: any, pointName: any, dataType?: any) => {
|
|
|
|
|
const pushPoint = (
|
|
|
|
|
deviceId: any,
|
|
|
|
|
deviceName: any,
|
|
|
|
|
pointId: any,
|
|
|
|
|
pointName: any,
|
|
|
|
|
dataType?: any
|
|
|
|
|
) => {
|
|
|
|
|
const dId = normalizeToString(deviceId)
|
|
|
|
|
if (!dId) return
|
|
|
|
|
const group = deviceGroups.get(dId) ?? { deviceId: dId, deviceName: String(deviceName ?? ''), points: [] }
|
|
|
|
|
const group = deviceGroups.get(dId) ?? {
|
|
|
|
|
deviceId: dId,
|
|
|
|
|
deviceName: String(deviceName ?? ''),
|
|
|
|
|
points: []
|
|
|
|
|
}
|
|
|
|
|
if (!group.deviceName) group.deviceName = String(deviceName ?? '')
|
|
|
|
|
const pId = normalizeToString(pointId)
|
|
|
|
|
if (!pId) {
|
|
|
|
|
deviceGroups.set(dId, group)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
group.points.push({ id: `${dId}:${pId}`, name: `${group.deviceName}: ${String(pointName ?? '')}`.trim(), dataType })
|
|
|
|
|
group.points.push({
|
|
|
|
|
id: `${dId}:${pId}`,
|
|
|
|
|
name: `${group.deviceName}: ${String(pointName ?? '')}`.trim(),
|
|
|
|
|
dataType
|
|
|
|
|
})
|
|
|
|
|
deviceGroups.set(dId, group)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isNonEmptyArray(list) && ((list[0] as any)?.deviceId !== undefined || (list[0] as any)?.deviceName !== undefined)) {
|
|
|
|
|
; (list as any[]).forEach((row) => {
|
|
|
|
|
if (
|
|
|
|
|
isNonEmptyArray(list) &&
|
|
|
|
|
((list[0] as any)?.deviceId !== undefined || (list[0] as any)?.deviceName !== undefined)
|
|
|
|
|
) {
|
|
|
|
|
;(list as any[]).forEach((row) => {
|
|
|
|
|
const deviceId = row?.deviceId ?? row?.devId ?? row?.device_id
|
|
|
|
|
const deviceName = row?.deviceName ?? row?.devName ?? row?.device_name
|
|
|
|
|
const points =
|
|
|
|
|
@ -289,7 +312,7 @@ const loadDevicePointTree = async () => {
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
} else if (isNonEmptyArray(list)) {
|
|
|
|
|
; (list as any[]).forEach((row) => {
|
|
|
|
|
;(list as any[]).forEach((row) => {
|
|
|
|
|
const deviceId = row?.deviceId ?? row?.devId
|
|
|
|
|
const deviceName = row?.deviceName ?? row?.devName
|
|
|
|
|
const pointId = row?.pointId ?? row?.id
|
|
|
|
|
@ -346,7 +369,7 @@ const open = async (type: string, id?: number) => {
|
|
|
|
|
try {
|
|
|
|
|
formData.value = await EnergyDeviceApi.getEnergyDevice(id)
|
|
|
|
|
if (!Array.isArray((formData.value as any).operationRulesVOList)) {
|
|
|
|
|
; (formData.value as any).operationRulesVOList = [
|
|
|
|
|
;(formData.value as any).operationRulesVOList = [
|
|
|
|
|
{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
@ -369,11 +392,11 @@ const submitForm = async () => {
|
|
|
|
|
const base = formData.value as unknown as EnergyDeviceVO
|
|
|
|
|
const payload: any = {
|
|
|
|
|
...(base as any),
|
|
|
|
|
deviceTypeName: typeList.value.find(item => item.id === base.deviceTypeId)?.name,
|
|
|
|
|
deviceTypeName: typeList.value.find((item) => item.id === base.deviceTypeId)?.name,
|
|
|
|
|
operationRulesVOList: buildOperationRulesPayload()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const org = findOrgNode(analysisTree.value ?? [], base.orgId)
|
|
|
|
|
const org = findOrgNode(orgSelectTree.value ?? [], base.orgId)
|
|
|
|
|
if (org) {
|
|
|
|
|
payload.orgName = org.name
|
|
|
|
|
}
|
|
|
|
|
@ -410,7 +433,9 @@ const resetForm = () => {
|
|
|
|
|
orgId: undefined,
|
|
|
|
|
orgName: undefined,
|
|
|
|
|
rules: undefined,
|
|
|
|
|
operationRulesVOList: [{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }]
|
|
|
|
|
operationRulesVOList: [
|
|
|
|
|
{ deviceId: undefined, pointId: undefined, operator: undefined, pointValue: undefined }
|
|
|
|
|
]
|
|
|
|
|
}
|
|
|
|
|
formRef.value?.resetFields()
|
|
|
|
|
}
|
|
|
|
|
@ -421,25 +446,26 @@ onMounted(async () => {
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
const loadAnalysis = async () => {
|
|
|
|
|
if (analysisList.value.length > 0) {
|
|
|
|
|
if (orgSelectTree.value.length > 0) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
analysisLoading.value = true
|
|
|
|
|
try {
|
|
|
|
|
const res: any = await OrganizationApi.deviceParameterAnalysis({ showDevices: 2 })
|
|
|
|
|
const list = Array.isArray(res) ? res : Array.isArray(res?.data) ? res.data : []
|
|
|
|
|
analysisList.value = list as OrgAnalysisNode[]
|
|
|
|
|
const res = await DeviceLineApi.getDeviceLineTree()
|
|
|
|
|
orgSelectTree.value = (Array.isArray(res) ? res : []) as OrgSelectNode[]
|
|
|
|
|
} finally {
|
|
|
|
|
analysisLoading.value = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleDeviceTypeChange = () => {
|
|
|
|
|
formData.value.unitName = typeList.value.find(item => item.id === formData.value.deviceTypeId)?.unit
|
|
|
|
|
formData.value.unitName = typeList.value.find(
|
|
|
|
|
(item) => item.id === formData.value.deviceTypeId
|
|
|
|
|
)?.unit
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const handleOrgChange = () => {
|
|
|
|
|
const org = findOrgNode(analysisTree.value ?? [], formData.value.orgId)
|
|
|
|
|
const org = findOrgNode(orgSelectTree.value ?? [], formData.value.orgId)
|
|
|
|
|
formData.value.orgName = org?.name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -452,7 +478,9 @@ const handlePointSelected = (index: number, val: any) => {
|
|
|
|
|
const [deviceIdStr, pointIdStr] = val.split(':')
|
|
|
|
|
const deviceId = Number(deviceIdStr)
|
|
|
|
|
const pointId = Number(pointIdStr)
|
|
|
|
|
formData.value.operationRulesVOList[index].deviceId = Number.isNaN(deviceId) ? undefined : deviceId
|
|
|
|
|
formData.value.operationRulesVOList[index].deviceId = Number.isNaN(deviceId)
|
|
|
|
|
? undefined
|
|
|
|
|
: deviceId
|
|
|
|
|
formData.value.operationRulesVOList[index].pointId = Number.isNaN(pointId) ? undefined : pointId
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -501,17 +529,17 @@ const hydratePointValues = () => {
|
|
|
|
|
const validateRules = (callback: any) => {
|
|
|
|
|
const list = formData.value.operationRulesVOList ?? []
|
|
|
|
|
if (!list.length) {
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesRequired')))
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesRequired')))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
for (let i = 0; i < list.length; i++) {
|
|
|
|
|
const r = list[i] as any
|
|
|
|
|
if (!r?.deviceId || !r?.pointId) {
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesPointRequired')))
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesPointRequired')))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (i > 0 && !list[i - 1]?.operator) {
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesOperatorRequired')))
|
|
|
|
|
callback(new Error(t('EnergyManagement.EnergyDevice.validatorRulesOperatorRequired')))
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
const dt = findPointDataType(r.deviceId, r.pointId)
|
|
|
|
|
@ -528,6 +556,6 @@ const validateRules = (callback: any) => {
|
|
|
|
|
|
|
|
|
|
<style scoped>
|
|
|
|
|
.energy-device-dialog-form :deep(.el-form-item__label) {
|
|
|
|
|
min-width: 100px;
|
|
|
|
|
min-width: 100px;
|
|
|
|
|
}
|
|
|
|
|
</style>
|
|
|
|
|
|