feat: 告警中心告警配置40%

This commit is contained in:
leiqiaochu 2023-02-24 17:23:36 +08:00
parent 1003130a4c
commit 6a275ee983
7 changed files with 353 additions and 59 deletions

View File

@ -18,4 +18,20 @@ export const remove = (id:string) => server.remove(`/alarm/config/${id}`);
/**
*
*/
export const _execute = (data:any) => server.post('/scene/batch/_execute',data)
export const _execute = (data:any) => server.post('/scene/batch/_execute',data);
/**
*
*/
export const getScene = (params:Record<string,any>) => server.get('/scene/_query/no-paging?paging=false',params);
/**
*
*/
export const getTargetTypes = () => server.get('/alarm/config/target-type/supports');
/**
*
*/
export const save = (data:any) =>server.post('/alarm/config',data);
/**
*
*/
export const detail = (id:string) => server.get(`/alarm/config/${id}`);

View File

@ -5,4 +5,6 @@ export const modify = (id: string, data: any) => server.put(`/scene/${id}`, data
export const save = (data: any) => server.post(`/scene`, data)
export const detail = (id: string) => server.get(`/scene/${id}`)
export const detail = (id: string) => server.get(`/scene/${id}`)
export const query = (data: any) => server.post('/scene/_query/',data);

View File

@ -0,0 +1,203 @@
<template>
<div>
<a-form layout="vertical" :rules="rule" :model="form" ref="formRef">
<a-row :gutter="24">
<a-col :span="12">
<a-form-item label="名称" name="name">
<a-input
placeholder="请输入名称"
v-model:value="form.name"
></a-input> </a-form-item
></a-col>
<a-col :span="12">
<a-form-item label="类型" name="targetType">
<a-select
:options="options"
v-model:value="form.targetType"
:disabled="selectDisable"
></a-select>
</a-form-item>
</a-col>
</a-row>
<a-form-item label="级别" name="level">
<a-radio-group v-model:value="form.level">
<a-radio-button
v-for="(item, index) in levelOption"
:key="index"
:value="item.value"
>
<div
style="
text-align: center;
margin-top: 10px;
font-size: 15px;
width: 90%;
"
>
<img
:src="getImage(`/alarm/alarm${index + 1}.png`)"
style="height: 40px"
alt=""
/>{{ item.label }}
</div>
</a-radio-button>
</a-radio-group>
</a-form-item>
<a-form-item label="说明" name="description">
<a-textarea v-model:value="form.description"></a-textarea>
</a-form-item>
<a-button type="primary" @click="handleSave" :loading="loading"
>保存</a-button
>
</a-form>
</div>
</template>
<script lang="ts" setup>
import { getTargetTypes, save, detail } from '@/api/rule-engine/configuration';
import { queryLevel } from '@/api/rule-engine/config';
import { query } from '@/api/rule-engine/scene';
import { getImage } from '@/utils/comm';
import { message } from 'ant-design-vue';
import { useMenuStore } from '@/store/menu';
import { useRoute } from 'vue-router';
import { Store } from 'jetlinks-store';
const route = useRoute();
const id = route.query?.id;
let selectDisable = ref(false);
const queryData = () => {
if (id) {
detail(id).then((res) => {
if (res.status === 200) {
form.level = res?.result?.level;
form.name = res?.result?.name;
form.targetType = res?.result?.targetType;
form.description = res?.result?.description;
Store.set('configuration-data', res.result);
query({
terms: [
{
terms: [
{
column: 'id',
termType: 'alarm-bind-rule',
value: id,
},
],
type: 'and',
},
],
sorts: [
{
name: 'createTime',
order: 'desc',
},
],
}).then((resq) => {
if (resq.status === 200) {
selectDisable.value = !!resq.result.data?.length;
}
});
}
});
}
};
const rule = {
name: [
{
required: true,
message: '请输入名称',
},
{
max: 64,
message: '最多输入64个字符',
},
],
targetType: [
{
required: true,
message: '请选择类型',
},
],
level: [
{
required: true,
message: '请选择级别',
},
],
description: [
{
max: 200,
message: '最多可输入200个字符',
},
],
};
let form = reactive({
level: '',
targetType: '',
name: '',
description: '',
});
let options = ref();
let levelOption = ref();
let loading = ref(false);
const formRef = ref();
const menuStory = useMenuStore();
const getSupports = async () => {
let res = await getTargetTypes();
if (res.status === 200) {
options.value = res.result.map(
(item: { id: string; name: string }) => ({
label: item.name,
value: item.id,
}),
);
}
};
getSupports();
const getLevel = () => {
queryLevel().then((res) => {
if (res.status === 200) {
levelOption.value = res.result?.levels
?.filter((i: any) => i?.level && i?.title)
.map((item: { level: number; title: string }) => ({
label: item.title,
value: item.level,
}));
}
});
};
getLevel();
const handleSave = async () => {
loading.value = true;
formRef.value
.validate()
.then(async () => {
const res = await save(form);
loading.value = false;
if (res.status === 200) {
message.success('操作成功');
menuStory.jumpPage(
'rule-engine/Alarm/Configuration/Save',
{},
{ id: res.result?.id },
);
if (!id) {
Store.set('configuration-data', res.result);
}
}
})
.catch((error) => {
loading.value = false;
console.log(error);
});
};
queryData();
</script>
<style lang="less" scoped>
.ant-radio-button-wrapper {
margin: 10px 15px 0 0;
width: 125px;
height: 100%;
}
</style>

View File

@ -0,0 +1,9 @@
<template>
<div>123</div>
</template>
<script lang="ts" setup>
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,23 @@
<template>
<page-container>
<a-card>
<a-tabs v-model:activeKey="activeKey">
<a-tab-pane key="1" tab="基础配置">
<Base/>
</a-tab-pane>
<a-tab-pane key="2" tab="关联场景联动">
<Scene></Scene>
</a-tab-pane>
<a-tab-pane key="3" tab="告警记录"></a-tab-pane>
</a-tabs>
</a-card>
</page-container>
</template>
<script lang="ts" setup>
import Base from './Base/index.vue';
import Scene from './Scene/index.vue'
const activeKey = ref('2');
</script>
<style lang="less" scoped>
</style>

View File

@ -2,7 +2,7 @@
<page-container>
<div>
<Search
:columns="query.columns"
:columns="columns"
target="device-instance"
@search="handleSearch"
></Search>
@ -13,6 +13,7 @@
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
}"
:params="params"
>
<template #headerTitle>
<a-space>
@ -41,23 +42,27 @@
</slot>
</template>
<template #content>
<h3 style="font-weight: 600">
{{ slotProps.name }}
</h3>
<Ellipsis>
<span style="font-weight: 600; font-size: 16px">
{{ slotProps.name }}
</span>
</Ellipsis>
<a-row>
<a-col :span="12">
<div class="content-des-title">
关联场景联动
</div>
<div class="rule-desc">
{{ (slotProps?.scene || []).map((item: any) => item?.name).join(',') || '' }}
</div>
<Ellipsis
><div>
{{ (slotProps?.scene || []).map((item: any) => item?.name).join(',') || '' }}
</div></Ellipsis
>
</a-col>
<a-col :span="12">
<div class="content-des-title">
告警级别
</div>
<div class="rule-desc">
<div>
{{ (Store.get('default-level') || []).find((item: any) => item?.level === slotProps.level)?.title ||
slotProps.level }}
</div>
@ -200,6 +205,7 @@ import {
_disable,
remove,
_execute,
getScene,
} from '@/api/rule-engine/configuration';
import { queryLevel } from '@/api/rule-engine/config';
import { Store } from 'jetlinks-store';
@ -207,6 +213,8 @@ import type { ActionsType } from '@/components/Table/index.vue';
import { message } from 'ant-design-vue';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import encodeQuery from '@/utils/encodeQuery';
import { useStorage } from '@vueuse/core';
const params = ref<Record<string, any>>({});
let isAdd = ref<number>(0);
let title = ref<string>('');
@ -217,35 +225,104 @@ const columns = [
title: '名称',
dataIndex: 'name',
key: 'name',
search: {
type: 'string',
},
},
{
title: '类型',
dataIndex: 'targetType',
key: 'targetType',
scopedSlots: true,
search: {
type: 'select',
options: [
{
label: '产品',
value: 'product',
},
{
label: '设备',
value: 'device',
},
{
label: '组织',
value: 'org',
},
{
label: '其他',
value: 'other',
},
],
},
},
{
title: '告警级别',
dataIndex: 'level',
key: 'level',
scopedSlots: true,
search: {
type: 'select',
options: async () => {
const res = await queryLevel();
if (res.status === 200) {
return (res?.result?.levels || [])
.filter((i: any) => i?.level && i?.title)
.map((item: any) => ({
label: item.title,
value: item.level,
}));
}
return [];
},
},
},
{
title: '关联场景联动',
dataIndex: 'sceneId',
wdith: 250,
scopedSlots: true,
search: {
type: 'select',
options: async () => {
const res = await getScene(
encodeQuery({
sorts: { createTime: 'desc' },
}),
);
if(res.status === 200){
return res.result.map((item:any) => ({label:item.name, value:item.id}))
}
return [];
},
},
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
scopedSlots: true,
search: {
type: 'select',
options: [
{
label: '正常',
value: 'enabled',
},
{
label: '禁用',
value: 'disabled',
},
],
},
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
search:{
type:'string',
}
},
{
title: '操作',
@ -261,44 +338,6 @@ const map = {
org: '组织',
other: '其他',
};
const query = {
columns: [
{
title: '名称',
dataIndex: 'name',
key: 'name',
search: {
type: 'string',
},
},
{
title: '状态',
dataIndex: 'state',
key: 'state',
search: {
type: 'select',
options: [
{
label: '正常',
value: 'enabled',
},
{
label: '禁用',
value: 'disabled',
},
],
},
},
{
title: '说明',
key: 'description',
dataIndex: 'description',
search: {
type: 'string',
},
},
],
};
const handleSearch = (e: any) => {
params.value = e;
};
@ -357,9 +396,7 @@ const getActions = (
icon: 'EditOutlined',
onClick: () => {
title.value = '编辑';
isAdd.value = 2;
nextTick(() => {});
menuStory.jumpPage('rule-engine/Alarm/Configuration/Save',{},{id:data.id});
},
},
{
@ -423,17 +460,12 @@ const getActions = (
return actions.filter((i: ActionsType) => i.key !== 'view');
return actions;
};
const add = () =>{
// menuStory.jumpPage()
}
const add = () => {
menuStory.jumpPage('rule-engine/Alarm/Configuration/Save');
};
</script>
<style lang="less" scoped>
.content-des-title {
font-size: 12px;
}
.rule-desc {
white-space: nowrap; /*强制在同一行内显示所有文本直到文本结束或者遭遇br标签对象才换行。*/
overflow: hidden; /*超出部分隐藏*/
text-overflow: ellipsis; /*隐藏部分以省略号代替*/
}
</style>

View File

@ -0,0 +1,9 @@
<template>
<div></div>
</template>
<script lang="ts" setup>
</script>
<style lang="less" scoped>
</style>