|
@@ -1,24 +1,92 @@
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
-import { ref, useTemplateRef } from 'vue';
|
|
|
|
-import dayjs from 'dayjs';
|
|
|
|
|
|
+import { onMounted, ref, useTemplateRef } from 'vue';
|
|
|
|
+import { message } from 'ant-design-vue';
|
|
|
|
+import dayjs, { Dayjs } from 'dayjs';
|
|
|
|
|
|
import ConfirmModal from '@/components/ConfirmModal.vue';
|
|
import ConfirmModal from '@/components/ConfirmModal.vue';
|
|
import SvgIcon from '@/components/SvgIcon.vue';
|
|
import SvgIcon from '@/components/SvgIcon.vue';
|
|
|
|
+import { useDictData } from '@/hooks/dict-data';
|
|
|
|
+import { useRequest } from '@/hooks/request';
|
|
import { t } from '@/i18n';
|
|
import { t } from '@/i18n';
|
|
|
|
+import { addAlarmEvent } from '@/api';
|
|
|
|
+import { DictCode } from '@/constants';
|
|
|
|
|
|
import AlarmConditions from './AlarmConditions.vue';
|
|
import AlarmConditions from './AlarmConditions.vue';
|
|
|
|
+import AlarmExecution from './AlarmExecution.vue';
|
|
|
|
|
|
-import type { Rule } from 'ant-design-vue/es/form';
|
|
|
|
-import type { AlarmForm } from '@/types';
|
|
|
|
|
|
+import type { FormInstance, Rule } from 'ant-design-vue/es/form';
|
|
|
|
+import type { AlarmEventItem, AlarmForm, ExecutionAction, TriggerConditionItem } from '@/types';
|
|
|
|
+
|
|
|
|
+const { handleRequest } = useRequest();
|
|
|
|
+const { dictData: alarmCondition, getDictData: getAlarmCondition } = useDictData(DictCode.AlarmCondition);
|
|
|
|
+const { dictData: executionAction, getDictData: getExecutionAction } = useDictData(DictCode.ExecutionAction);
|
|
|
|
+const { dictData: alarmRepeatTime, getDictData: getAlarmRepeatTime } = useDictData(DictCode.AlarmRepeatTime);
|
|
|
|
+const { dictData: alarmAlgOperator, getDictData: getAlarmAlgOperator } = useDictData(DictCode.AlarmAlgOperator);
|
|
|
|
+const { dictData: alarmDeviceState, getDictData: getAlarmDeviceState } = useDictData(DictCode.AlarmDeviceState);
|
|
|
|
+const { dictData: alarmNotifyMethod, getDictData: getAlarmNotifyMethod } = useDictData(DictCode.AlarmNotifyMethod);
|
|
|
|
|
|
const modalComponentRef = useTemplateRef('modalComponent');
|
|
const modalComponentRef = useTemplateRef('modalComponent');
|
|
|
|
+const formRef = ref<FormInstance>();
|
|
|
|
+const triggerConditionRefs = ref<InstanceType<typeof AlarmConditions>[]>([]);
|
|
|
|
+const judgmentConditionRefs = ref<InstanceType<typeof AlarmConditions>[]>([]);
|
|
|
|
+const executionActionRefs = ref<InstanceType<typeof AlarmConditions>[]>([]);
|
|
|
|
+
|
|
|
|
+const triggerConditionList = ref<TriggerConditionItem[]>([
|
|
|
|
+ {
|
|
|
|
+ type: 0,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAlgOperator: '',
|
|
|
|
+ alarmThreshold: '',
|
|
|
|
+ alarmDeviceState: '',
|
|
|
|
+ alarmScheduledTime: undefined,
|
|
|
|
+ alarmRepeatTime: '',
|
|
|
|
+ },
|
|
|
|
+]);
|
|
|
|
+
|
|
|
|
+const judgmentConditionList = ref<TriggerConditionItem[]>([
|
|
|
|
+ {
|
|
|
|
+ type: 1,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAlgOperator: '',
|
|
|
|
+ alarmThreshold: '',
|
|
|
|
+ alarmDeviceState: '',
|
|
|
|
+ alarmScheduledTime: undefined,
|
|
|
|
+ alarmRepeatTime: '',
|
|
|
|
+ },
|
|
|
|
+]);
|
|
|
|
+
|
|
|
|
+const executionActionList = ref<ExecutionAction[]>([
|
|
|
|
+ {
|
|
|
|
+ type: 2,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAdjustmentValue: '',
|
|
|
|
+ alarmContact: undefined,
|
|
|
|
+ alarmAlertContent: '',
|
|
|
|
+ alarmWaitTime: undefined,
|
|
|
|
+ alarmNotifyMethod: '',
|
|
|
|
+ },
|
|
|
|
+]);
|
|
const historyOpen = ref<boolean>(false);
|
|
const historyOpen = ref<boolean>(false);
|
|
const alarmOpen = ref<boolean>(false);
|
|
const alarmOpen = ref<boolean>(false);
|
|
// 日期时间格式
|
|
// 日期时间格式
|
|
const dateFormat = 'HH:mm';
|
|
const dateFormat = 'HH:mm';
|
|
const alarmForm = ref<AlarmForm>({
|
|
const alarmForm = ref<AlarmForm>({
|
|
- name: '',
|
|
|
|
|
|
+ eventName: '',
|
|
time: [dayjs(), dayjs()],
|
|
time: [dayjs(), dayjs()],
|
|
|
|
+ conditionLogic: 0,
|
|
|
|
+ enabled: true,
|
|
});
|
|
});
|
|
const historyData = ref([
|
|
const historyData = ref([
|
|
{
|
|
{
|
|
@@ -79,7 +147,7 @@ const alarmQuery = ref({
|
|
});
|
|
});
|
|
|
|
|
|
const rules: Record<string, Rule[]> = {
|
|
const rules: Record<string, Rule[]> = {
|
|
- name: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
|
|
|
|
|
|
+ eventName: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
|
|
time: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
|
|
time: [{ required: true, message: t('common.cannotEmpty'), trigger: 'change' }],
|
|
};
|
|
};
|
|
const historyColumns = [
|
|
const historyColumns = [
|
|
@@ -194,7 +262,143 @@ const confirm = () => {
|
|
};
|
|
};
|
|
const switchPages = () => {};
|
|
const switchPages = () => {};
|
|
const switchHistoryPages = () => {};
|
|
const switchHistoryPages = () => {};
|
|
-const addTriggerConditions = () => {};
|
|
|
|
|
|
+const addTriggerConditions = () => {
|
|
|
|
+ triggerConditionList.value.push({
|
|
|
|
+ type: 0,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAlgOperator: '',
|
|
|
|
+ alarmThreshold: '',
|
|
|
|
+ alarmDeviceState: '',
|
|
|
|
+ alarmScheduledTime: undefined,
|
|
|
|
+ alarmRepeatTime: '',
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const addJudgmentConditions = () => {
|
|
|
|
+ judgmentConditionList.value.push({
|
|
|
|
+ type: 1,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAlgOperator: '',
|
|
|
|
+ alarmThreshold: '',
|
|
|
|
+ alarmDeviceState: '',
|
|
|
|
+ alarmScheduledTime: undefined,
|
|
|
|
+ alarmRepeatTime: '',
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const addExecutionConditions = () => {
|
|
|
|
+ executionActionList.value.push({
|
|
|
|
+ type: 2,
|
|
|
|
+ subType: '',
|
|
|
|
+ groupId: undefined,
|
|
|
|
+ childGroupId: undefined,
|
|
|
|
+ deviceId: undefined,
|
|
|
|
+ paramCode: '',
|
|
|
|
+ alarmAdjustmentValue: '',
|
|
|
|
+ alarmContact: undefined,
|
|
|
|
+ alarmAlertContent: '',
|
|
|
|
+ alarmWaitTime: undefined,
|
|
|
|
+ alarmNotifyMethod: '',
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 添加格式转换
|
|
|
|
+const formatDate = (date: Dayjs) => date.format('HH:mm');
|
|
|
|
+
|
|
|
|
+const deleteTriggerClick = (index: number) => {
|
|
|
|
+ if (index === 0) {
|
|
|
|
+ return message.warning('触发条件不能为空!');
|
|
|
|
+ }
|
|
|
|
+ triggerConditionList.value.splice(index, 1);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const deleteJudgmentClick = (index: number) => {
|
|
|
|
+ judgmentConditionList.value.splice(index, 1);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const deleteExecutionClick = (index: number) => {
|
|
|
|
+ if (index === 0) {
|
|
|
|
+ return message.warning('执行动作不能为空!');
|
|
|
|
+ }
|
|
|
|
+ executionActionList.value.splice(index, 1);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const convertAtoB = (arr: TriggerConditionItem[] | ExecutionAction[]): AlarmEventItem[] => {
|
|
|
|
+ return arr.map((item) => {
|
|
|
|
+ // 解构固定字段和剩余属性
|
|
|
|
+ const { type, subType, groupId, childGroupId, deviceId, paramCode, ...dynamicFields } = item;
|
|
|
|
+
|
|
|
|
+ // 转换动态字段到 dataList
|
|
|
|
+ const dataList = Object.entries(dynamicFields)
|
|
|
|
+ .map(([code, value]) => ({
|
|
|
|
+ code,
|
|
|
|
+ value: String(value), // 确保值转为字符串
|
|
|
|
+ })) // 过滤空值(空字符串、null、undefined)
|
|
|
|
+ .filter(({ value }) => value !== '' && value != null && value != 'undefined');
|
|
|
|
+
|
|
|
|
+ // 返回符合 AlarmEventItem 结构的对象
|
|
|
|
+ return {
|
|
|
|
+ type,
|
|
|
|
+ subType,
|
|
|
|
+ groupId,
|
|
|
|
+ childGroupId,
|
|
|
|
+ deviceId,
|
|
|
|
+ paramCode,
|
|
|
|
+ dataList,
|
|
|
|
+ };
|
|
|
|
+ });
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const okConfirm = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const allComponents = [...triggerConditionRefs.value, ...judgmentConditionRefs.value, ...executionActionRefs.value];
|
|
|
|
+ await Promise.all(allComponents.map((child) => child.formRefSubmit()));
|
|
|
|
+
|
|
|
|
+ formRef.value
|
|
|
|
+ ?.validate()
|
|
|
|
+ .then(() => {
|
|
|
|
+ handleRequest(async () => {
|
|
|
|
+ const { eventName, time, enabled, conditionLogic } = alarmForm.value;
|
|
|
|
+ const data = time.map(formatDate) || [];
|
|
|
|
+ const triggerList = convertAtoB(triggerConditionList.value);
|
|
|
|
+ const judgmentList = convertAtoB(judgmentConditionList.value);
|
|
|
|
+ const executionList = convertAtoB(executionActionList.value);
|
|
|
|
+ await addAlarmEvent({
|
|
|
|
+ eventName,
|
|
|
|
+ startTime: data[0],
|
|
|
|
+ endTime: data[1],
|
|
|
|
+ enabled,
|
|
|
|
+ conditionLogic: conditionLogic === 1 ? true : false,
|
|
|
|
+ triggerConditionList: triggerList,
|
|
|
|
+ judgmentConditionList: judgmentList,
|
|
|
|
+ executionActionList: executionList,
|
|
|
|
+ });
|
|
|
|
+ alarmOpen.value = false;
|
|
|
|
+ });
|
|
|
|
+ })
|
|
|
|
+ .catch(() => {});
|
|
|
|
+ } catch {
|
|
|
|
+ console.log('存在验证未通过的表单');
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+onMounted(() => {
|
|
|
|
+ handleRequest(async () => {
|
|
|
|
+ await getAlarmCondition();
|
|
|
|
+ await getExecutionAction();
|
|
|
|
+ await getAlarmRepeatTime();
|
|
|
|
+ await getAlarmAlgOperator();
|
|
|
|
+ await getAlarmDeviceState();
|
|
|
|
+ await getAlarmNotifyMethod();
|
|
|
|
+ });
|
|
|
|
+});
|
|
</script>
|
|
</script>
|
|
|
|
|
|
<template>
|
|
<template>
|
|
@@ -252,10 +456,10 @@ const addTriggerConditions = () => {};
|
|
/>
|
|
/>
|
|
</AFlex>
|
|
</AFlex>
|
|
</div>
|
|
</div>
|
|
- <AModal v-model:open="alarmOpen" title="预警条件添加" width="920px" :mask-closable="false">
|
|
|
|
|
|
+ <AModal v-model:open="alarmOpen" title="预警条件添加" width="920px" :mask-closable="false" @ok="okConfirm">
|
|
<AForm ref="formRef" class="alarm-modal" :model="alarmForm" label-align="left" layout="vertical" :rules="rules">
|
|
<AForm ref="formRef" class="alarm-modal" :model="alarmForm" label-align="left" layout="vertical" :rules="rules">
|
|
- <AFormItem label="事件名称" name="name">
|
|
|
|
- <AInput v-model:value="alarmForm.name" placeholder="请输入" class="query-input query-bottom" />
|
|
|
|
|
|
+ <AFormItem label="事件名称" name="eventName">
|
|
|
|
+ <AInput v-model:value="alarmForm.eventName" placeholder="请输入" class="query-input query-bottom" />
|
|
</AFormItem>
|
|
</AFormItem>
|
|
<AFormItem label="生效时间段" name="time">
|
|
<AFormItem label="生效时间段" name="time">
|
|
<ATimeRangePicker
|
|
<ATimeRangePicker
|
|
@@ -266,7 +470,19 @@ const addTriggerConditions = () => {};
|
|
/>
|
|
/>
|
|
</AFormItem>
|
|
</AFormItem>
|
|
<div class="alarm-text">当任一情况发生</div>
|
|
<div class="alarm-text">当任一情况发生</div>
|
|
- <AlarmConditions :alarm-form="alarmForm" />
|
|
|
|
|
|
+
|
|
|
|
+ <div v-for="(item, index) in triggerConditionList" :key="index">
|
|
|
|
+ <AlarmConditions
|
|
|
|
+ ref="triggerConditionRefs"
|
|
|
|
+ @deleteClick="deleteTriggerClick"
|
|
|
|
+ :index="index"
|
|
|
|
+ :form="item"
|
|
|
|
+ :alarm-condition="alarmCondition"
|
|
|
|
+ :alarm-repeat-time="alarmRepeatTime"
|
|
|
|
+ :alarm-alg-operator="alarmAlgOperator"
|
|
|
|
+ :alarm-device-state="alarmDeviceState"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
|
|
<AButton type="primary" ghost class="icon-button button-top" @click="addTriggerConditions">
|
|
<AButton type="primary" ghost class="icon-button button-top" @click="addTriggerConditions">
|
|
<AFlex align="center">
|
|
<AFlex align="center">
|
|
@@ -274,7 +490,58 @@ const addTriggerConditions = () => {};
|
|
<span> 添加触发条件 </span>
|
|
<span> 添加触发条件 </span>
|
|
</AFlex></AButton
|
|
</AFlex></AButton
|
|
>
|
|
>
|
|
|
|
+ <br />
|
|
|
|
+
|
|
|
|
+ <ASelect class="status-style" v-model:value="alarmForm.conditionLogic">
|
|
|
|
+ <ASelectOption :value="0">且满足任一状态</ASelectOption>
|
|
|
|
+ <ASelectOption :value="1">且满足全部状态</ASelectOption>
|
|
|
|
+ </ASelect>
|
|
|
|
+ <br />
|
|
|
|
+ <div v-for="(item, index) in judgmentConditionList" :key="index">
|
|
|
|
+ <AlarmConditions
|
|
|
|
+ ref="judgmentConditionRefs"
|
|
|
|
+ @deleteClick="deleteJudgmentClick"
|
|
|
|
+ :index="index"
|
|
|
|
+ :form="item"
|
|
|
|
+ :alarm-condition="alarmCondition"
|
|
|
|
+ :execution-action="executionAction"
|
|
|
|
+ :alarm-repeat-time="alarmRepeatTime"
|
|
|
|
+ :alarm-alg-operator="alarmAlgOperator"
|
|
|
|
+ :alarm-device-state="alarmDeviceState"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <AButton type="primary" ghost class="icon-button button-top" @click="addJudgmentConditions">
|
|
|
|
+ <AFlex align="center">
|
|
|
|
+ <SvgIcon name="plus" />
|
|
|
|
+ <span> 添加判断条件 </span>
|
|
|
|
+ </AFlex></AButton
|
|
|
|
+ >
|
|
|
|
+ <br />
|
|
|
|
+
|
|
|
|
+ <div class="execute-text">就</div>
|
|
|
|
+ <div v-for="(item, index) in executionActionList" :key="index">
|
|
|
|
+ <AlarmExecution
|
|
|
|
+ ref="executionActionRefs"
|
|
|
|
+ @deleteClick="deleteExecutionClick"
|
|
|
|
+ :index="index"
|
|
|
|
+ :form="item"
|
|
|
|
+ :execution-action="executionAction"
|
|
|
|
+ :alarm-notify-method="alarmNotifyMethod"
|
|
|
|
+ />
|
|
|
|
+ </div>
|
|
|
|
+
|
|
|
|
+ <AButton type="primary" ghost class="icon-button button-top" @click="addExecutionConditions">
|
|
|
|
+ <AFlex align="center">
|
|
|
|
+ <SvgIcon name="plus" />
|
|
|
|
+ <span> 添加执行动作 </span>
|
|
|
|
+ </AFlex></AButton
|
|
|
|
+ >
|
|
</AForm>
|
|
</AForm>
|
|
|
|
+ <AFlex align="center" class="enable-style">
|
|
|
|
+ <div class="enable-text">启用</div>
|
|
|
|
+ <ASwitch v-model:checked="alarmForm.enabled" />
|
|
|
|
+ </AFlex>
|
|
</AModal>
|
|
</AModal>
|
|
<AModal v-model:open="historyOpen" title="历史报警" width="920px" :footer="null">
|
|
<AModal v-model:open="historyOpen" title="历史报警" width="920px" :footer="null">
|
|
<ATable :columns="historyColumns" :data-source="historyData" :pagination="false">
|
|
<ATable :columns="historyColumns" :data-source="historyData" :pagination="false">
|
|
@@ -310,6 +577,35 @@ const addTriggerConditions = () => {};
|
|
</template>
|
|
</template>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
<style lang="scss" scoped>
|
|
|
|
+.enable-text {
|
|
|
|
+ margin-right: 32px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-style: normal;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ line-height: 24px;
|
|
|
|
+ color: #333;
|
|
|
|
+ text-align: left;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.enable-style {
|
|
|
|
+ margin-top: 40px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.execute-text {
|
|
|
|
+ margin-top: 40px;
|
|
|
|
+ font-size: 16px;
|
|
|
|
+ font-style: normal;
|
|
|
|
+ font-weight: 500;
|
|
|
|
+ line-height: 24px;
|
|
|
|
+ color: #333;
|
|
|
|
+ text-align: left;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.status-style {
|
|
|
|
+ width: 192px;
|
|
|
|
+ margin-top: 40px;
|
|
|
|
+}
|
|
|
|
+
|
|
.query-bottom {
|
|
.query-bottom {
|
|
margin-bottom: 8px;
|
|
margin-bottom: 8px;
|
|
}
|
|
}
|