Files
SaaS-lib/hx-ai-intelligent/src/view/alarmManagement/alarmSettings/equipmentAlarm/editConfigureDeviceAlarm.vue
2024-07-19 14:13:01 +08:00

522 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<ns-drawer
v-model:visible="visible"
width="520"
:title="infoObject?.id ? '编辑告警规则' : '新增告警规则'"
:footer-style="{ textAlign: 'right' }"
:ok="btnClick"
:cancel="handleClose"
placement="right"
@close="handleClose">
<div style="padding: 18px; width: 100%; overflow: hidden">
<a-form ref="formRef" :model="infoObject" :rules="rules">
<a-form-item ref="site" label="站点" name="site">
<a-tree-select
v-model:value="infoObject.site"
show-search
style="width: 100%"
:dropdown-style="{ maxHeight: '400px', overflow: 'auto' }"
placeholder="请选择站点"
allow-clear
tree-default-expand-all
:field-names="{
children: 'linkList',
label: 'orgName',
value: 'orgId',
}"
:tree-data="siteDataTree"
tree-node-filter-prop="orgName" />
</a-form-item>
<a-form-item label="设备类型" name="deviceType">
<a-cascader
v-model:value="infoObject.deviceType"
:options="deviceTypeTreeData"
:field-names="{
children: 'children',
label: 'deviceType',
value: 'id',
}"
:show-search="{ filterDeviceType }"
@change="selectDeviceType"
placeholder="请选择设备类型" />
</a-form-item>
<a-form-item label="设备名称" name="deviceId">
<a-select
v-model:value="infoObject.deviceId"
:disabled="!(infoObject && infoObject.deviceType && infoObject.deviceType.length > 0)"
style="width: 100%"
:autoClearSearchValue="true"
@change="selectDevice"
placeholder="请选择设备名称">
<template v-for="(item, index) in deviceNameTreeData" :key="index">
<a-select-option :value="item.id">
{{ item.deviceName }}
</a-select-option>
</template>
</a-select>
</a-form-item>
<a-form-item label="设备点位" name="devicePoint">
<a-select
v-model:value="infoObject.devicePoint"
show-search
placeholder="请选择设备点位"
style="width: 100%"
:disabled="!infoObject?.deviceId"
:options="devicePointData"
:filter-option="filterDevicePoint" />
</a-form-item>
<a-form-item label="启用规则">
<a-switch
:checked="infoObject.enableRules === 1 ? true : false"
:class="{
'blue-background': infoObject.enableRules === 1 ? true : false,
'grey-background': infoObject.enableRules === 1 ? false : true,
}"
@click="clickSwitch" />
</a-form-item>
<a-form-item label="取值类型" name="valueType">
<a-select
v-model:value="infoObject.valueType"
placeholder="请选择取值类型"
style="width: 100%"
:options="qzOptions" />
</a-form-item>
<a-form-item label="异常描述" name="abnormalDescription">
<a-textarea
v-model:value="infoObject.abnormalDescription"
style="height: 32px"
placeholder="请输入异常描述"
:autoSize="{ minRows: 1, maxRows: 1 }"
show-count
:maxlength="30" />
</a-form-item>
<a-form-item label="规则类型" name="ruleType">
<a-radio-group v-model:value="infoObject.ruleType">
<a-radio value="1"> (and) </a-radio>
<a-radio value="2"> (or) </a-radio>
</a-radio-group>
</a-form-item>
<template v-for="index in infoObject.alarmList?.length" :key="index">
<div
style="
width: 100%;
display: flex;
margin-left: 42px;
padding: 12px;
border-color: #ff4d4f !important;
">
<span style="line-height: 32px">{{ `逻辑${index}:` }}</span>
<a-select
v-model:value="infoObject.alarmList[index - 1].logic"
style="width: 70px; margin-left: 12px"
:options="ljOptions" />
<span style="line-height: 32px; margin-left: 32px">{{ `数值${index}:` }}</span>
<a-input
style="width: 65px; margin-left: 6px"
type="number"
v-model:value="infoObject.alarmList[index - 1].num" />
<div
style="width: 70px; align-items: center; cursor: pointer"
@click="deleteAlarmList(index - 1)">
<img
style="width: 14px; margin: 0 12px"
src="https://files.axshare.com/gsc/4T0UQR/5a/e6/81/5ae6813d499c422383c7a15dd956523f/images/设备规则/u72.svg?pageId=cbce6e61-bc6a-4283-802d-993fce6151c0" />
</div>
</div>
<div
v-if="
infoObject.alarmList[index - 1]?.num === null ||
infoObject.alarmList[index - 1]?.logic === null
"
style="width: 100%; color: #ff4d4f; text-align: center; margin-bottom: 5px">
请选择正确的逻辑{{ index }} 或 输入正确的数值{{ index }}
</div>
</template>
<div
v-if="infoObject?.alarmList?.length < 2"
style="width: 100%; color: #ff4d4f; text-align: center; margin-bottom: 5px">
逻辑至少2条
</div>
<div style="width: 100%; margin-top: 12px; display: flex; justify-content: flex-end">
<a-button type="primary" @click="addAlarmList"> 新增</a-button>
</div>
</a-form>
</div>
</ns-drawer>
</template>
<script lang="ts" setup>
import { NsMessage } from '/nerv-lib/component';
import { ref } from 'vue';
import type { SelectProps } from 'ant-design-vue';
import type { ShowSearchType } from 'ant-design-vue/es/cascader';
import { device } from '/@/api/deviceManage';
import { deviceAlarms } from '/@/api/alarmSettings/deviceAlarms';
import { http } from '/nerv-lib/util';
import { async } from '@antv/x6/lib/registry/marker/async';
const visible = ref(false);
// 父级数据
const equipmentAlarm = ref({});
//表单数据
const infoObject = ref({
site: null,
ruleType: null,
abnormalDescription: null,
deviceType: [],
devicePoint: null,
valueType: null,
deviceId: null,
enableRules: 0,
alarmList: [{ logic: null, num: null, isDelete: 0 }],
});
//删除的逻辑列表
const delAlarmList = ref([]);
const formRef = ref();
//组织数
const orgId = ref('');
const result = JSON.parse(sessionStorage.getItem('ORGID')!);
orgId.value = result;
//站点数
const siteDataTree = ref([]);
//设备类型树
let deviceTypeTreeData = ref([]);
//设备树
let deviceNameTreeData = ref([]);
//选择设备类型方法
const selectDeviceType = (value: any, selectedOptions: any) => {
//获取该类型设备
getDevicePage({
orgId: orgId.value,
deviceCode: selectedOptions[selectedOptions.length - 1].code,
pageNum: 1,
pageSize: 999,
});
};
//选择设备方法
const selectDevice = () => {
getDevicePoint({ id: infoObject.value.deviceId });
};
//获取设备列表
const getDevicePage = (value: any) => {
http.post(device.queryDevicePage, value).then((res) => {
if (res.msg === 'success') {
deviceNameTreeData.value = res.data.records;
}
});
};
//获取设备点位
const getDevicePoint = (value: any) => {
devicePointData.value = [];
http.post(device.queryDevicePoint, value).then((res) => {
if (res.msg === 'success') {
res.data.forEach((item: any) => {
devicePointData.value.push({
value: item.id,
label: item.code + ' ( ' + item.unit + ' ) ',
});
});
}
});
};
//设备点位
const devicePointData = ref([]);
//设备点位搜索
const filterDevicePoint = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//搜索设备类型
const filterDeviceType: ShowSearchType['filter'] = (inputValue: any, path: any) => {
return path.some(
(option: any) => option.deviceType.toLowerCase().indexOf(inputValue.toLowerCase()) > -1,
);
};
//取值类型
const qzOptions = ref<SelectProps['options']>([
{ value: 1, label: '实时值' },
{ value: 2, label: '平均值' },
]);
//逻辑
const ljOptions = ref<SelectProps['options']>([
{ value: 0, label: '≥' },
{ value: 1, label: '>' },
{ value: 2, label: '≤' },
{ value: 3, label: '<' },
{ value: 4, label: '=' },
]);
//开关
const clickSwitch = () => {
if (infoObject.value.enableRules === 1) {
infoObject.value.enableRules = 0;
} else {
infoObject.value.enableRules = 1;
}
};
const emit = defineEmits(['editObject']);
// 定义一个递归函数来查找每一级的id 设备类型回显 层级方法
function findParentIds(tree: any[], targetId: number, result: number[]): boolean {
for (let item of tree) {
if (item.children && item.children.length > 0) {
if (item.children.some((child: any) => child.id === targetId)) {
result.unshift(item.id); // 将当前节点的id添加到结果数组的最前面
return true; // 表示找到了目标节点的父节点
}
// 递归查找当前节点的子节点
if (findParentIds(item.children, targetId, result)) {
result.unshift(item.id); // 递归返回后将当前节点的id添加到结果数组的最前面
return true;
}
}
}
return false; // 没有找到目标节点
}
// 递归 获取当前 选择的设备类型 对象 用来获取设备列表
const findNodeById = (nodes: any, id: any) => {
for (let node of nodes) {
if (node.id === id) {
//获取设备树
getDevicePage({ orgId: orgId.value, code: node.code, pageNum: 1, pageSize: 99 });
return;
} else if (node.children.length > 0) {
const found = findNodeById(node.children, id);
if (found) {
//获取设备树
getDevicePage({ orgId: orgId.value, code: found.code, pageNum: 1, pageSize: 99 });
return;
}
}
}
return null; // 没有找到目标节点,返回 null
};
//父调子 页面显示方法
const toggle = async (value: any, info: any) => {
equipmentAlarm.value = info;
//获取设备类型
await http
.post(device.queryDeviceTree, { orgId: orgId.value, pageNum: 1, pageSize: 10 })
.then((res) => {
if (res.msg === 'success') {
deviceTypeTreeData.value = res.data;
}
});
// 获取站点数据
http.post('/carbon-smart/user/login/logInInfo', {}).then((res) => {
if (res.msg === 'success') {
siteDataTree.value = res.data.linkList;
}
});
//判断 是新增 还是修改
if (value) {
//获取详情接口
await http.post(deviceAlarms.configFindById, { id: value.id }).then((res) => {
if (res.msg === 'success') {
infoObject.value = res.data;
// 获取 选择的设备类型对象
let selectDevice = ref([Number(infoObject.value.deviceType)]);
findNodeById(deviceTypeTreeData.value, Number(infoObject.value.deviceType));
//获取设备点位
getDevicePoint({ id: infoObject.value.deviceId });
// 回显 选择设备类型
findParentIds(
deviceTypeTreeData.value,
Number(infoObject.value.deviceType),
selectDevice.value,
);
//枚举 需要重新赋值
if (
infoObject.value.hxAlarmRuleLogicList &&
infoObject.value.hxAlarmRuleLogicList.length > 0
) {
infoObject.value.hxAlarmRuleLogicList.forEach((item: any) => {
item.logic = item.logic.value;
});
}
infoObject.value.alarmList = infoObject.value.hxAlarmRuleLogicList || [];
delete infoObject.value.hxAlarmRuleLogicList;
infoObject.value.deviceType = selectDevice;
infoObject.value.valueType = infoObject.value.valueType.value;
infoObject.value.ruleType = infoObject.value.ruleType + '';
}
});
} else {
//获取设备树
infoObject.value = {
site: null,
ruleType: null,
abnormalDescription: null,
deviceType: [],
devicePoint: null,
valueType: null,
deviceId: null,
enableRules: 0,
alarmList: [{ logic: null, num: null, isDelete: 0 }],
};
}
visible.value = !visible.value;
};
//表单 判断规格
const rules = {
site: [{ required: true, message: '请选择站点', trigger: 'change' }],
deviceType: [{ required: true, message: '请选择设备类型', trigger: 'change' }],
enableRules: [{ required: true, message: '请选择启用规则', trigger: 'change' }],
deviceId: [{ required: true, message: '请选择设备名称', trigger: 'change' }],
devicePoint: [{ required: true, message: '请选择设备点位', trigger: 'change' }],
valueType: [{ required: true, message: '请选择取值类型', trigger: 'change' }],
ruleType: [{ required: true, message: '请选择规则类型', trigger: 'change' }],
abnormalDescription: [
{
required: true,
message: '请输入异常描述',
trigger: 'blur',
validator: (rules: any, abnormalDescription: any, cbfn: any) => {
if (abnormalDescription.trim() !== '') {
cbfn();
} else {
cbfn('告警标题不能为空');
}
},
},
],
alarm: [{ required: true, message: '请选择逻辑', trigger: 'blur' }],
number: [{ required: true, message: '请输入数值', trigger: 'blur' }],
};
// 确认按钮
const btnClick = () => {
infoObject.value.alarmList.forEach((item) => {
if (item.logic === null || item.num === null) {
return;
}
});
if (infoObject.value.alarmList.length < 2) {
NsMessage.error('请选择逻辑和数值');
return;
}
//数据是否验证通过
formRef.value.validate().then(() => {
let data = { ...infoObject.value };
// 配置关联id
data.equipmentAlarmId = equipmentAlarm.value.id;
// 逻辑列表
data.hxAlarmRuleLogicList = [...infoObject.value.alarmList, ...delAlarmList.value];
data.hxAlarmRuleLogicList.forEach((item) => {
const num = Number(item.num);
if (!isNaN(num)) {
item.num = Number(num.toFixed(2));
} else {
item.num = 0; // 可以设置为0或其他默认值
}
});
// 设备类型 只取最后一级的id
data.deviceType = infoObject.value.deviceType[infoObject.value.deviceType.length - 1];
data.ruleType = Number(data.ruleType);
data.errorCode = equipmentAlarm.value.errorCode;
delete data.alarmList;
// 发起 HTTP POST 请求
http
.post(deviceAlarms.configAddOrUpNewData, data)
.then((res) => {
if (res.msg === 'success') {
// 操作成功时的处理
if (data.id) {
NsMessage.success('告警规则编辑成功');
} else {
NsMessage.success('告警规则新增成功');
}
emit('editObject', null);
handleClose();
}
})
.catch((error) => {
// 错误处理
console.error('请求失败:', error);
});
});
};
//取消按钮
const handleClose = () => {
// 清楚校验错误信息
formRef.value.resetFields();
siteDataTree.value = [];
//对象清空
infoObject.value = {
site: null,
ruleType: null,
abnormalDescription: null,
deviceType: [],
devicePoint: null,
enableRules: 0,
alarmList: [{ logic: null, num: null, isDelete: 0 }],
};
visible.value = false;
//清空删除列表
delAlarmList.value = [];
};
// 新增逻辑列表
const addAlarmList = () => {
if (infoObject.value.alarmList) {
infoObject.value.alarmList.push({ logic: null, num: null, isDelete: 0 });
} else {
infoObject.value.alarmList = [{ logic: null, num: null, isDelete: 0 }];
}
};
// 删除 逻辑列表、
const deleteAlarmList = (index: number) => {
// 确保 index 在有效范围内
if (index < infoObject.value.alarmList.length && index >= 0) {
const alarmItemToDelete = infoObject.value.alarmList[index];
if (alarmItemToDelete?.id) {
// 添加到 delAlarmList 中,并标记为已删除
delAlarmList.value.push({ ...alarmItemToDelete, isDelete: 1 });
}
// 从 infoObject 中删除该元素
infoObject.value.alarmList.splice(index, 1);
}
};
defineExpose({
toggle,
handleClose,
formRef,
});
</script>
<style scoped lang="less">
.drawerContainer {
height: 100%;
display: flex;
justify-content: space-between;
}
.blue-background.ant-switch-checked {
background-color: linear-gradient(
180deg,
rgba(1, 206, 255, 1) 0%,
rgba(0, 150, 229, 1) 100%
) !important;
}
.grey-background.ant-switch {
background-color: grey !important;
}
.blue-background.ant-switch-checked .ant-switch-handle {
background-color: linear-gradient(
180deg,
rgba(1, 206, 255, 1) 0%,
rgba(0, 150, 229, 1) 100%
) !important;
}
.grey-background.ant-switch .ant-switch-handle {
background-color: grey !important;
}
:deep(.ant-form-item-label) {
z-index: 20;
text-align: right;
width: 23%;
}
</style>