alarmRules 模块开发及接口联调

This commit is contained in:
renpy 2023-07-26 18:08:28 +08:00
parent c4f890fd2c
commit f41826d681
9 changed files with 823 additions and 28 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -2,56 +2,667 @@
<div style="height: 100%;">
<div class="rules-header">
<div>
<a-button class="rules-add">
<a-button class="rules-add" @click="handleAdd">
<img class="icon-add" src="@/assets/images/global/add.png" alt="" />
<span style="margin-left: 10px;">
Create Alert Rulep
Create Alert Rule
</span>
</a-button>
<a-select style="width: 160px;margin-left: 10px;" v-bind="$attrs" show-arrow placeholder="select...">
<a-select
style="width: 200px;margin-left: 10px;"
:value="queryParams.station"
:options="stateOptions"
show-arrow
allowClear
placeholder="select..."
@change="onStateChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
<div slot="dropdownRender" slot-scope="menu">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 0;" />
<div
style="padding: 4px 12px; cursor: pointer;"
@mousedown="e => e.preventDefault()"
>
<a-checkbox v-model="allVal" @change="checkedAll"><span @click.prevent="handleClick">ALL</span></a-checkbox>
</div>
</div>
</a-select>
<a-select style="width: 160px;margin-left: 10px;" v-bind="$attrs" show-arrow placeholder="select...">
<a-select
style="width: 200px;margin-left: 10px;"
:value="queryParams.type"
:options="typeOptions"
show-arrow
allowClear
placeholder="select..."
@change="onTypeChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
<div slot="dropdownRender" slot-scope="menu">
<v-nodes :vnodes="menu" />
<a-divider style="margin: 0;" />
<div
style="padding: 4px 12px; cursor: pointer;"
@mousedown="e => e.preventDefault()"
>
<a-checkbox v-model="allVal" @change="checkedAll"><span @click.prevent="handleClick">ALL</span></a-checkbox>
</div>
</div>
</a-select>
<a-select
style="width: 200px;margin-left: 10px;"
:value="queryParams.name"
:options="nameOptions"
show-arrow
allowClear
placeholder="select..."
@change="onNameChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
<a-button class="search-btn" @click="onSearch">
<img class="icon-add" src="@/assets/images/global/search.png" alt="" />
<span style="margin-left: 10px;">
Search
</span>
</a-button>
</div>
<a-button class="rules-reset">
<a-button class="rules-reset" @click="resetQuery">
<img class="icon-add" src="@/assets/images/global/reset-pwd.png" alt="" />
<span style="margin-left: 10px;">
Refresh
</span>
</a-button>
</div>
<div class="rules-content">
<div class="monitor-list">
<div class="monitor-list-item" v-for="item in monitorList" :key="item.id">
<div class="monitor-list-item-title">
<div class="monitor-list-item-title-name">{{ item.name }}</div>
<div class="monitor-list-item-title-server">
<span style="color: #5b9cba;">{{ item.sourceType }}</span>
<a-tooltip>
<template slot="title">
{{ item.sourceName }}
</template>
<span style="color: #ade6ee;">{{ item.sourceName }}</span>
</a-tooltip>
</div>
</div>
<div class="monitor-list-item-content">
<div class="monitor-list-item-content-info">
{{ JSON.parse(item.operator).name }} {{ JSON.parse(item.operator).operator }} {{ JSON.parse(item.operator).threshold }}{{ JSON.parse(item.operator).units }}
</div>
<div :class="[item.enabled==1?'monitor-list-item-content-enable':'monitor-list-item-content-disable', 'monitor-list-item-content-btn']">
{{ item.enabled==1?"Enable":"Disabled" }}
</div>
</div>
<div class="monitor-list-item-footer">
<div class="monitor-list-item-footer-group">
<span style="color: #5b9cba;">Alert Contact Group</span>
<span style="color: #ade6ee;">{{ item.groupName }}</span>
</div>
<div class="monitor-list-item-footer-actions">
<span class="actions-edit" @click="editItem(item.id)"></span>
<span class="actions-delete" @click="deleteItem(item.id)"></span>
<span v-if="item.enabled==1" class="actions-enable">
</span>
<span v-if="item.enabled==0" class="actions-disable">
</span>
</div>
</div>
</div>
</div>
<a-pagination
size="small"
v-model="ipagination.current"
:pageSize="ipagination.pageSize"
:page-size-options="ipagination.pageSizeOptions"
show-size-changer
show-quick-jumper
:total="ipagination.total"
:show-total="(total, range) => `Total ${total} items Page ${ipagination.current} / ${Math.ceil(total / ipagination.pageSize)}`"
show-less-items
@change="handlePageChange"
@showSizeChange="handleSizeChange"
/>
</div>
<a-modal
:title="isAdd ? 'Add Rule' : 'Edit Rule'"
:width="845"
:key= modalKey
v-model="visible"
@cancel="onCancel"
>
<a-form-model
ref="ruleForm"
:model="form"
:rules="rules"
layout="vertical"
>
<a-row :gutter="[15,0]">
<a-col :span="12">
<a-form-model-item ref="sourceType" label="Source Type" prop="sourceType">
<a-select
:value="form.sourceType"
:options="typeOptions"
show-arrow
allowClear
placeholder="select..."
@change="onSourceTypeChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="source" label="Source" prop="sourceId">
<a-select
v-model="form.sourceId"
:options="sourceOptions"
show-arrow
allowClear
labelInValue
placeholder="select..."
@change="onSourceChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="[15,0]">
<a-col :span="12">
<a-form-model-item ref="alarmRule" label="Alarm Rule" prop="name">
<a-input v-model="form.name" />
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="monitorItem" label="Monitor Item" prop="itemId">
<a-select
v-model="form.itemId"
:options="itemOptions"
show-arrow
allowClear
labelInValue
placeholder="select..."
@change="onItemChange"
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="[15,0]">
<a-col :span="12">
<a-form-model-item ref="monitorItem" label="Logic Symbol" prop="operator">
<a-select
v-model="form.operator"
:options="operatorOptions"
show-arrow
allowClear
placeholder="select..."
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="threshold" label="Threshold" prop="threshold">
<a-input v-model="form.threshold" :suffix="units" />
</a-form-model-item>
</a-col>
</a-row>
<a-row :gutter="[15,0]">
<a-col :span="12">
<a-form-model-item ref="silenceCycle" label="Silence Cycle" prop="silenceCycle">
<a-select
v-model="form.silenceCycle"
:options="silenceCyclerOptions"
show-arrow
allowClear
placeholder="select..."
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
<a-col :span="12">
<a-form-model-item ref="contactGroup" label="Contact Group" prop="contactId">
<a-select
v-model="form.contactId"
:options="contactGroupOptions"
show-arrow
allowClear
placeholder="select..."
>
<img slot="suffixIcon" src="@/assets/images/global/select-down.png" alt="" />
</a-select>
</a-form-model-item>
</a-col>
</a-row>
</a-form-model>
<template slot="footer">
<a-space class="operators" :size="20">
<a-button type="success" @click="onSave">Save</a-button>
<a-button type="warn" @click="onCancel">Cancel</a-button>
</a-space>
</template>
</a-modal>
</div>
</template>
<script>
export default {
}
import { getAction,postAction,httpAction,deleteAction } from '@/api/manage'
import BoxTitle from '../../components/boxTitle.vue';
export default {
components: {
BoxTitle,
VNodes: {
functional: true,
render: (h, ctx) => ctx.props.vnodes,
},
},
data() {
return {
modalKey:"",
isAdd:true,
ipagination:{
current: 1,
pageSize: 9,
pageSizeOptions: ['9', '18', '27'],
showTotal: (total, range) => {
const { current, pageSize } = this.ipagination
return `Total ${total} items Page ${current} / ${Math.ceil(total / pageSize)}`
},
showQuickJumper: true,
showSizeChanger: true,
total: 0
},
visible:false,
queryParams: {
station: undefined,
type: undefined,
name: undefined
},
stateOptions: [
{
label: "禁用",
value: "0"
},
{
label: "启用",
value: "1"
}
],
typeOptions: [
{
label: "Server",
value: "Server"
},
{
label: "Database",
value: "Database"
},
{
label: "E-MAIL",
value: "Email"
},
],
nameOptions: [],
monitorList: [],
//
form: {
sourceType: "",
sourceId: "",
name: "",
itemId: "",
operator: "",
threshold: "",
silenceCycle: "",
contactId: "",
},
currId:"",
units: "",
sourceOptions: [],
operatorOptions: [
{
label: ">",
value: ">"
},
{
label: "<",
value: "<"
},
{
label: ">=",
value: ">="
},
{
label: "<=",
value: "<="
},
{
label: "==",
value: "=="
},
],
itemOptions: [],
silenceCyclerOptions: [
{
label: "5 minutes",
value: "300"
},
{
label: "15 minutes",
value: "900"
},
{
label: "30 minutes",
value: "1800"
},
{
label: "60 minutes",
value: "3600"
},
{
label: "3 hours",
value: "10800"
},
{
label: "6 hours",
value: "21600"
},
{
label: "12 hours",
value: "43200"
},
{
label: "24 hours",
value: "86400"
}
],
contactGroupOptions: [],
rules: {
sourceType: [
{ required: true, message: 'Please select a sourceType'},
],
sourceId: [
{ required: true, message: 'Please select a source'},
],
name: [
{ required: true, message: 'Please input alarmRule name'},
],
itemId: [
{ required: true, message: 'Please select a monitorItem'},
],
operator: [
{ required: true, message: 'Please select a logicSymbol'},
],
threshold: [
{ required: true, message: 'Please input threshold'},
],
silenceCycle: [
{ required: true, message: 'Please select a silenceCycle'},
],
contactId: [
{ required: true, message: 'Please select a contactGroup'},
],
}
}
},
mounted () {
this.getAlarmRulesPage()
this.getAlarmGroup()
},
methods: {
getAlarmSources(val) {
getAction("/alarmRule/getSources", {souceType:val}).then(res => {
if (res.success) {
this.nameOptions = this.sourceOptions = res.result.map(item => {
return {
label: item.sourceName,
value: item.sourceId
}
})
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
getAlarmRulesPage() {
let params = {
pageNo: this.ipagination.current,
pageSize: this.ipagination.pageSize,
enabled: this.queryParams.station,
sourceType: this.queryParams.type,
sourceId: this.queryParams.name
}
getAction("/alarmRule/findPage", params).then(res => {
if (res.success) {
this.monitorList = res.result.records
this.ipagination.total = res.result.total
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
onSearch() {
this.getAlarmRulesPage()
},
resetQuery() {
this.queryParams = {
station: undefined,
type: undefined,
name: undefined
}
},
handlePageChange(page, pageSize) {
this.ipagination.current = page
this.ipagination.pageSize = pageSize
this.getAlarmRulesPage()
},
handleSizeChange(current, size) {
this.ipagination.current = current
this.page.pageSize = size
this.getAlarmRulesPage()
},
onTypeChange(val) {
this.queryParams.type = val
if (val) {
this.getAlarmSources(val)
}
},
onStateChange(val) {
this.queryParams.station = val
},
onNameChange(val) {
this.queryParams.name = val
},
getUid() {
return (Math.random()+new Date().getTime()).toString(32).slice(0,8)
},
handleAdd() {
this.modalKey = this.getUid()
this.visible = true
this.isAdd = true
},
onSourceTypeChange(val) {
this.form.sourceType = val
this.getAlarmSources(val)
},
onSourceChange(val,option) {
this.form.sourceId = val
this.getItems(val.label)
},
getItems(val) {
getAction("/alarmRule/getItems", {sourceName:val}).then(res => {
if (res.success) {
this.itemOptions = res.result.map(item => {
return {
label: item.name,
value: item.itemId,
units:item.units
}
})
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
onItemChange(val, option) {
this.form.itemId = val
this.units = option.data.props.units
},
getAlarmGroup() {
let params = {
pageNo: 1,
pageSize: 9999
}
getAction("/alarmContactGroup/findPage", params).then(res => {
if (res.success) {
this.contactGroupOptions = res.result.records.map(item => {
return {
label: item.name,
value: item.id
}
})
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
onSave() {
this.$refs.ruleForm.validate((valid) => {
if (valid) {
let params = {
silenceCycle:this.form.silenceCycle,
contactId:this.form.contactId,
sourceId:this.form.sourceId.key,
sourceType:this.form.sourceType,
itemId:this.form.itemId.key,
rule: {
name: this.form.itemId.label,
operator: this.form.operator,
threshold: this.form.threshold,
units: this.units,
},
name: this.form.name,
id: this.isAdd?"":this.currId
}
if (this.isAdd) {
postAction("/alarmRule/create", params).then(res => {
if (res.success) {
this.visible = false
this.$message.success("success")
this.getAlarmRulesPage()
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
} else {
httpAction("/alarmRule/update", params, "put").then(res => {
if (res.success) {
this.visible = false
this.$message.success("success")
this.getAlarmRulesPage()
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
}
}
});
},
onCancel() {
this.resetForm()
this.units = ""
this.visible = false
},
editItem(id) {
getAction("/alarmRule/findInfo", {alarmRuleId:id}).then(async res => {
if (res.success) {
let result_1 = await getAction("/alarmRule/getSources", { souceType: res.result.sourceType })
if (result_1.success) {
this.sourceOptions = result_1.result.map(item => {
return {
label: item.sourceName,
value: item.sourceId
}
})
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
let result_2 = await getAction("/alarmRule/getItems", {sourceName:res.result.sourceName})
if (result_2.success) {
this.itemOptions = result_2.result.map(item => {
return {
label: item.name,
value: item.itemId,
units:item.units
}
})
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
this.visible = true
this.isAdd = false
this.form.sourceType = res.result.sourceType
this.form.sourceId = {
key: res.result.sourceId,
label: res.result.sourceName
}
this.form.name = res.result.name
this.form.itemId = {
key: res.result.itemId,
label: JSON.parse(res.result.operator).name
}
this.form.operator = JSON.parse(res.result.operator).operator
this.form.threshold = JSON.parse(res.result.operator).threshold
this.units = JSON.parse(res.result.operator).units
this.form.silenceCycle = res.result.silenceCycle
this.form.contactId = res.result.contactId
this.currId = res.result.id
} else {
this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
deleteItem(id) {
let _this = this
this.$confirm({
title: 'Are you sure to delete this item?',
onOk() {
deleteAction("/alarmRule/deleteById", {alarmRuleId:id}).then(res => {
if (res.success) {
_this.$message.success("success")
_this.getAlarmRulesPage()
} else {
_this.$message.warning("This operation fails. Contact your system administrator")
}
})
},
onCancel() {
console.log('Cancel');
},
});
},
resetForm() {
this.$refs.ruleForm.resetFields();
},
},
}
</script>
<style lang="less" scoped>
.operators {
width: 100%;
justify-content: center;
.ant-btn {
width: 92px;
}
}
/deep/.ant-modal-title{
letter-spacing: 1px;
}
.ant-select {
.ant-select-arrow-icon {
transition: all 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
}
&-open {
.ant-select-arrow-icon {
transform: rotate(180deg);
}
}
}
.ant-select-dropdown-content{
position: relative;
background: #03353f;
}
.rules-header{
height: 50px;
border-top: 1px solid rgba(13, 235, 201, 0.3);
@ -61,12 +672,20 @@
align-items: center;
justify-content: space-between;
padding: 0 10px;
background: rgba(12, 235, 201, 0.05);
.rules-add{
background-color: #1397a3;
font-family: ArialMT;
color: #ffffff;
border: none;
}
.search-btn{
margin-left: 10px;
background-color: #1397a3;
font-family: ArialMT;
color: #ffffff;
border: none;
}
.rules-reset{
background-color: #1397a3;
font-family: ArialMT;
@ -75,4 +694,135 @@
float: right;
}
}
.rules-content{
height: calc(100% - 65px);
margin-left: 20px;
position: relative;
overflow: hidden;
.monitor-list{
height: calc(100% - 40px);
overflow: auto;
display: flex;
flex-wrap:wrap;
justify-content: space-between;
align-content: flex-start;
&-item{
width: 32.76%;
height: 275px;
// margin-top: 15px;
background-color: rgba(2, 40, 43, 0.5);
border: solid 1px rgba(65, 111, 127, 0.5);
position: relative;
margin-bottom: 15px;
&-title{
height: 50px;
padding: 0 15px 0 20px;
background-color: rgba(13, 109, 118, 0.2);
border-bottom: solid 1px rgba(65, 111, 127, 0.2);
display: flex;
justify-content: space-between;
line-height: 50px;
font-family: ArialMT;
&-name{
font-size: 16px;
color: #00bded;
}
&-server{
width: 55%;
font-size: 14px;
text-align: right;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
&-content{
padding: 15px 20px;
&-info{
font-family: ArialMT;
font-size: 16px;
color: #ade6ee;
}
&-btn{
margin-top: 10px;
display: inline-block;
padding: 3px 10px;
}
&-enable{
background-color: #098839;
}
&-disable{
background-color: #8a8a8a;
}
}
&-footer{
width: 100%;
height: 32px;
position: absolute;
bottom: 10px;
padding: 0 20px;
display: flex;
align-items: center;
justify-content: space-between;
&-group{
font-family: ArialMT;
font-size: 14px;
}
&-actions{
display: flex;
align-items: center;
span{
display: inline-block;
width: 26px;
height: 26px;
margin-left: 5px;
cursor: pointer;
}
.actions-edit{
background: url(~@/assets/images/abnormalAlarm/edit.png) no-repeat;
background-size: 100% 100%;
&:hover{
background: url(~@/assets/images/abnormalAlarm/edit-active.png) no-repeat;
background-size: 100% 100%;
}
}
.actions-delete{
background: url(~@/assets/images/abnormalAlarm/delete.png) no-repeat;
background-size: 100% 100%;
&:hover{
background: url(~@/assets/images/abnormalAlarm/delete-active.png) no-repeat;
background-size: 100% 100%;
}
}
.actions-enable{
background: url(~@/assets/images/abnormalAlarm/enable.png) no-repeat;
background-size: 100% 100%;
&:hover{
background: url(~@/assets/images/abnormalAlarm/enable-active.png) no-repeat;
background-size: 100% 100%;
}
}
.actions-disable{
background: url(~@/assets/images/abnormalAlarm/disable.png) no-repeat;
background-size: 100% 100%;
&:hover{
background: url(~@/assets/images/abnormalAlarm/disable-active.png) no-repeat;
background-size: 100% 100%;
}
}
}
}
}
&::after{
content: '';
width: 32.76%;
}
}
.ant-pagination{
position: absolute;
left: 50%;
bottom: 0;
transform: translateX(-50%);
}
}
</style>

View File

@ -0,0 +1,45 @@
<template>
<div class="chart-title">
<span>{{ title }}</span>
<img src="@/assets/images/abnormalAlarm/title_right.png" alt="">
</div>
</template>
<script>
export default {
props: {
title: {
type: String,
default: ""
}
}
}
</script>
<style lang="less" scoped>
.chart-title{
height: 40px;
font-family: MicrogrammaD-MediExte;
font-size: 18px;
font-weight: bold;
line-height: 36px;
letter-spacing: 1px;
color: #0cebc9;
border-bottom: 4px solid rgba(12, 235, 201, 0.2);
border-top: 1px solid rgba(12, 235, 201, 0.2);
position: relative;
// display: flex;
// justify-content: space-between;
span{
display: inline-block;
padding: 0 15px;
background-color: rgba(12, 235, 201, 0.05);
}
img{
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
}
}
</style>