Commit 632b7528 authored by 张耀's avatar 张耀

feat:

预警管理静态页面开发和部分接口对接
parent eeb30804
<template> <template>
<div>指标配置详情</div> <div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container bg-scroll">
<gap-title :hasLine="true" title="基本信息"></gap-title>
<div class="info">
<Info :labelData="labelData" :valueData="info">
<template #status="{ item, valueData }">
<span class="status-body">
<span class="status" :class="`status-${valueData.status}`"></span>
<span>{{ STATUS_OBJ[valueData[item.prop]] }}</span>
</span>
</template>
</Info>
</div>
<gap-title :hasLine="true" title="指标表达式"></gap-title>
<div class="info">
<div class="indicator-expression">
<bg-code-editor v-model="info.indicator_expression" disabled></bg-code-editor>
</div>
</div>
<gap-title :hasLine="true" title="预警范围"></gap-title>
<div class="info">
<bg-table border ref="ruletable" :headers="warningScopeHeaders" :rows="warningScopeRows" height="100%">
<template #metric="{ row }">
<span>{{ row.metric_name }}/{{ row.metric_label }}</span>
</template>
<template #is_required="{ row }">
<span>{{ row.is_required ? "" : "" }}</span>
</template>
<template #is_linked="{ row }">
<span>{{ row.is_linked ? "" : "" }}</span>
</template>
</bg-table>
</div>
<gap-title :hasLine="true" title="预警规则类型"></gap-title>
<div class="info">
<Info :labelData="rule_label" :valueData="rule_data">
<template #alert_rule_type="{ valueData }">
<span>
{{ ruleTypeOptions[valueData.alert_rule_type] }}
</span>
</template>
</Info>
</div>
<gap-title :hasLine="true" title="高级配置"> </gap-title>
<div class="info">
<Info :labelData="advanced_label" :valueData="advanced_data">
<template #inspection_cycle="{ valueData }">
<span>{{ valueData.inspection_cycle }}分钟</span>
</template>
</Info>
</div>
</div>
</div>
</template> </template>
<script setup></script> <script setup>
import gapTitle from "@/components/gap-title.vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import Info from "@/components/warn-detail/info.vue";
import { METHODS } from "@/components/manual-distribution/env.js";
const STATUS_OBJ = {
enabled: "启用",
disabled: "禁用",
};
const labelData = [
[
{
label: "预警分类",
prop: "warning_target",
},
{
label: "预警对象",
prop: "warning_type",
},
],
[
{
label: "预警指标",
prop: "warning_index",
},
{
label: "启用状态",
prop: "status",
},
],
[
{
label: "创建人",
prop: "create_by",
},
{
label: "创建时间",
prop: "create_time",
},
],
[
{
label: "更新时间",
prop: "update_time",
},
],
];
const info = {
warning_rule_name: "服务中断推送规则1",
status: "enabled",
warning_target: "容器云",
warning_type: "容器集群",
warning_index: "CPU使用率",
create_by: "admin",
create_time: "2020-01-01 00:00:00",
update_time: "2020-01-01 00:00:00",
indicator_expression: 'shttp_requests_total{method="GET",$pod$}',
};
const rule_label = [
[
{
prop: "alert_rule_type",
label: "预警规则类型",
},
],
];
const rule_data = {
alert_rule_type: "1",
};
const ruleTypeOptions = {
empty: "",
1: "百分比范围",
2: "毫秒范围",
3: "秒范围",
4: "个范围",
5: "温度范围",
};
const advanced_label = [
[
{
prop: "duration",
label: "持续时间",
},
],
[
{
prop: "inspection_cycle",
label: "检查周期",
},
],
];
const advanced_data = {
duration: "直接产生预警",
inspection_cycle: "1",
};
const ticket_push_label = [
[
{
prop: "notification_method",
label: "预警通知方式",
},
],
[
{
prop: "push_num",
label: "消息推送次数",
},
],
[
{
prop: "push_frequency",
label: "消息推送频率",
},
],
];
const ticket_push_data = {
notification_method: ["1", "2"],
push_num: "10次",
push_frequency: "60分钟",
};
const warningScopeHeaders = [
{
prop: "variable_name",
label: "变量名称",
},
{
prop: "metric",
label: "指标标签",
},
{
prop: "chinese_name",
label: "中文名称",
},
{
prop: "is_required",
label: "是否必填",
},
{
prop: "is_linked",
label: "是否联动",
},
];
const warningScopeRows = [
{
variable_name: "$pod$",
metric_name: "shttp_requests_total",
metric_label: "pod",
chinese_name: "demoString",
is_required: true,
is_linked: true,
},
{
variable_name: "$pod$",
metric_name: "shttp_requests_total",
metric_label: "pod",
chinese_name: "demoString",
is_required: true,
is_linked: true,
},
];
const pushHeaders = [
{
prop: "warning_threshold",
label: "预警阈值",
},
{
prop: "risk_level",
label: "风险程度",
},
];
const pushRows = [
{
warning_threshold: "12% - 50% ",
risk_level: "较大风险",
},
{
warning_threshold: "50% - 100% ",
risk_level: "重大风险",
},
];
</script>
<style lang="scss" scoped></style> <style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px;
min-height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
.main_container {
height: 100%;
padding: 24px;
:deep(.gap-title) {
margin-bottom: 16px;
}
.info {
max-width: 1072px;
width: 100%;
padding: 0 8px 0;
&:not(:last-child) {
padding-bottom: 24px;
}
.push-lists {
margin-top: 16px;
}
.indicator-expression {
height: 300px;
width: 100%;
:deep(.vue-ace-editor) {
margin-top: 0;
}
}
}
}
}
.status {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
$statusObj: (
enabled: #48ad97,
disabled: #9e9e9e,
);
@each $status, $color in $statusObj {
&-#{$status} {
background-color: $color;
}
}
}
.status-body {
display: flex;
align-items: center;
}
</style>
...@@ -236,7 +236,7 @@ const getTableRows = () => { ...@@ -236,7 +236,7 @@ const getTableRows = () => {
}; };
const goDetail = (row) => { const goDetail = (row) => {
router.push({ router.push({
path: "/forewarning/rule-set/detail", path: "/forewarning/indicator-config/detail",
query: { query: {
id: row.id, id: row.id,
class_id: node.value.data.id, class_id: node.value.data.id,
......
...@@ -17,8 +17,9 @@ ...@@ -17,8 +17,9 @@
default-expand-all default-expand-all
:data="slideTree" :data="slideTree"
:current-node-key="selectId" :current-node-key="selectId"
node-key="id" node-key="class_id"
empty-text="暂无数据" empty-text="暂无数据"
:props="treeProps"
:highlight-current="true" :highlight-current="true"
:expand-on-click-node="false" :expand-on-click-node="false"
:filter-node-method="filterNode" :filter-node-method="filterNode"
...@@ -69,7 +70,8 @@ ...@@ -69,7 +70,8 @@
<el-form :model="state.form_target" ref="add_warn_target_form" :rules="state.target_rules" label-width="80px"> <el-form :model="state.form_target" ref="add_warn_target_form" :rules="state.target_rules" label-width="80px">
<el-form-item label="预警分类" prop="type"> <el-form-item label="预警分类" prop="type">
<el-select style="flex: 1" v-model="state.form_target.type" placeholder="请选择预警分类" filterable> <el-select style="flex: 1" v-model="state.form_target.type" placeholder="请选择预警分类" filterable>
<el-option v-for="item in slideTree" :key="item.id" :label="item.label" :value="item.id"> </el-option> <el-option v-for="item in slideTree" :key="item.class_id" :label="item.class_name" :value="item.class_id">
</el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="预警对象" prop="target"> <el-form-item label="预警对象" prop="target">
...@@ -101,6 +103,8 @@ ...@@ -101,6 +103,8 @@
<script setup> <script setup>
import { nextTick, onBeforeMount, reactive, ref } from "vue"; import { nextTick, onBeforeMount, reactive, ref } from "vue";
import GapTitle from "@/components/gap-title.vue"; import GapTitle from "@/components/gap-title.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const props = defineProps({ const props = defineProps({
modelValue: { modelValue: {
type: Object, type: Object,
...@@ -109,55 +113,31 @@ const props = defineProps({ ...@@ -109,55 +113,31 @@ const props = defineProps({
}); });
const search = ref(""); const search = ref("");
let slideTree = ref([]); let slideTree = ref([]);
const treeProps = {
// 组织树获取数据规则
children: "children",
label: "class_name",
};
const treeRef = ref(null); const treeRef = ref(null);
const selectId = ref(""); const selectId = ref("");
const getSlideTree = async () => { const getSlideTree = () => {
slideTree.value = [ const params = {
{ page: 1,
id: 1, page_size: 100000000000,
label: "容器云", };
children: [ axios.get("/v1/api/alert_class/list", { params }).then(async (res) => {
{ if (res.data.code == 200) {
id: 11, slideTree.value = res.data.data.list;
label: "容器集群",
},
{
id: 12,
label: "容器节点",
},
{
id: 13,
label: "工作负载",
},
{
id: 4,
label: "网关",
},
],
},
{
id: 2,
label: "机房",
},
{
id: 3,
label: "机柜",
},
{
id: 4,
label: "服务器",
},
{
id: 5,
label: "数据库/达梦数据库",
},
];
await nextTick(); await nextTick();
treeRef.value.setCurrentKey(slideTree.value[0].children[0].id); treeRef.value.setCurrentKey(slideTree.value[0]?.children?.[0].class_id);
setTimeout(() => { const node = treeRef.value.getNode(slideTree.value[0]?.children?.[0]);
const node = treeRef.value.getNode(slideTree.value[0].children[0]); if (node) {
treeNodeChoose(slideTree.value[0].children[0], node); treeNodeChoose(slideTree.value[0].children[0], node);
}, 1000); }
} else {
ElMessage.error(res.data.msg);
}
});
}; };
const filterNode = (value, data) => { const filterNode = (value, data) => {
if (!value) return data; if (!value) return data;
...@@ -209,8 +189,8 @@ const operations = { ...@@ -209,8 +189,8 @@ const operations = {
label: () => "上移", label: () => "上移",
disabled: (node, data) => { disabled: (node, data) => {
let arr = getBrotherNodes(node); let arr = getBrotherNodes(node);
let id = data.id; let id = data.class_id;
let i = arr.findIndex((e) => e.id == id); let i = arr.findIndex((e) => e.class_id == id);
return 0 == i; return 0 == i;
}, },
}, },
...@@ -218,8 +198,8 @@ const operations = { ...@@ -218,8 +198,8 @@ const operations = {
label: () => "下移", label: () => "下移",
disabled: (node, data) => { disabled: (node, data) => {
let arr = getBrotherNodes(node); let arr = getBrotherNodes(node);
let id = data.id; let id = data.class_id;
let i = arr.findIndex((e) => e.id == id); let i = arr.findIndex((e) => e.class_id == id);
return arr.length - 1 == i; return arr.length - 1 == i;
}, },
}, },
...@@ -240,38 +220,49 @@ const Operation = (key, node, data) => { ...@@ -240,38 +220,49 @@ const Operation = (key, node, data) => {
if (node.level == 1) { if (node.level == 1) {
addWarnType.value = true; addWarnType.value = true;
await nextTick(); await nextTick();
state.form.name = data.label; state.form.name = data.class_name;
} else { } else {
addWarnTarget.value = true; addWarnTarget.value = true;
await nextTick(); await nextTick();
state.form_target.type = activeTree.value.data.id; state.form_target.type = activeTree.value.data.class_id;
state.form_target.target = data.label; state.form_target.target = data.class_name;
} }
isEditWarnType.value = true; isEditWarnType.value = true;
}, },
2: () => { 2: () => {
addWarnTarget.value = true; addWarnTarget.value = true;
isEditWarnType.value = false; isEditWarnType.value = false;
state.form_target.type = activeTree.value.data.id; state.form_target.type = activeTree.value.data.class_id;
}, },
3: () => { 3: () => {
delWarnType.value = true; delWarnType.value = true;
}, },
4: () => { 4: () => {
let arr = getBrotherNodes(node); move(data.class_id, "up");
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let prev = arr[i - 1];
}, },
5: () => { 5: () => {
let arr = getBrotherNodes(node); move(data.class_id, "down");
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let next = arr[i + 1];
}, },
}; };
operation_handled_fn[key](); operation_handled_fn[key]();
}; };
const move = (class_id, type) => {
const params = {
class_id,
};
axios.put(`/v1/api/alert_class/move/${type}`, params).then((res) => {
if (res.data.code == 200) {
let text = {
up: "上移",
down: "下移",
};
ElMessage.success(`${text[type]}成功`);
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
};
const add_warn_type_form = ref(null); const add_warn_type_form = ref(null);
const add_warn_target_form = ref(null); const add_warn_target_form = ref(null);
const state = reactive({ const state = reactive({
...@@ -298,8 +289,23 @@ const Cancel = async () => { ...@@ -298,8 +289,23 @@ const Cancel = async () => {
const Save = () => { const Save = () => {
add_warn_type_form.value.validate((valid) => { add_warn_type_form.value.validate((valid) => {
if (valid) { if (valid) {
console.log(state.form); const params = {
class_name: state.form.name,
parent_id: 0,
};
if (isEditWarnType.value) {
params.class_id = activeTree.value.own.class_id;
}
let method = isEditWarnType.value ? "put" : "post";
axios[method]("/v1/api/alert_class", params).then((res) => {
if (res.data.code == 200) {
ElMessage.success("预警分类新建成功");
Cancel(); Cancel();
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
} else { } else {
return false; return false;
} }
...@@ -313,8 +319,23 @@ const CancelAddWarnTarget = async () => { ...@@ -313,8 +319,23 @@ const CancelAddWarnTarget = async () => {
const SaveAddWarnTarget = () => { const SaveAddWarnTarget = () => {
add_warn_target_form.value.validate((valid) => { add_warn_target_form.value.validate((valid) => {
if (valid) { if (valid) {
console.log(state.form_target); const params = {
Cancel(); class_name: state.form_target.target,
parent_id: state.form_target.type,
};
if (isEditWarnType.value) {
params.class_id = activeTree.value.own.class_id;
}
let method = isEditWarnType.value ? "put" : "post";
axios[method]("/v1/api/alert_class", params).then((res) => {
if (res.data.code == 200) {
ElMessage.success("预警对象新建成功");
CancelAddWarnTarget();
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
} else { } else {
return false; return false;
} }
...@@ -324,8 +345,21 @@ const CancelDel = () => { ...@@ -324,8 +345,21 @@ const CancelDel = () => {
delWarnType.value = false; delWarnType.value = false;
}; };
const ConfirmDel = () => { const ConfirmDel = () => {
console.log(activeTree.value.own); axios
.delete("/v1/api/alert_class", {
data: {
class_id: activeTree.value.own.class_id,
},
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success("删除成功");
CancelDel(); CancelDel();
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
}; };
onBeforeMount(() => { onBeforeMount(() => {
getSlideTree(); getSlideTree();
......
...@@ -155,6 +155,7 @@ ...@@ -155,6 +155,7 @@
v-model="closeWarningDialog" v-model="closeWarningDialog"
width="400px" width="400px"
:before-close="cancelCloseWarningDialog"> :before-close="cancelCloseWarningDialog">
<div style="padding-top: 20px">
<el-form ref="closeForm" :model="closeFormData" :rules="closeRules" label-width="80px" class="bg_form"> <el-form ref="closeForm" :model="closeFormData" :rules="closeRules" label-width="80px" class="bg_form">
<el-form-item label="关闭备注" prop="close_notes"> <el-form-item label="关闭备注" prop="close_notes">
<el-input <el-input
...@@ -166,10 +167,14 @@ ...@@ -166,10 +167,14 @@
resize="vertical" resize="vertical"
placeholder="请输入内容"></el-input> placeholder="请输入内容"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="" prop="close_remind" style="margin-bottom: 0px"> <el-form-item label="" class="no-el-label" prop="close_remind" style="margin-bottom: 0px">
<el-checkbox v-model="closeFormData.close_remind" label="三天内将不再推送该预警信息" /> <el-checkbox v-model="closeFormData.close_remind">
<div>三天内将不再自动推送该告警信息给处置人员,</div>
<div>可手动推送,但告警数据依然会出现</div>
</el-checkbox>
</el-form-item> </el-form-item>
</el-form> </el-form>
</div>
<template v-slot:footer> <template v-slot:footer>
<div class="apaas_button"> <div class="apaas_button">
<el-button type="default" @click="cancelCloseWarningDialog">取消</el-button> <el-button type="default" @click="cancelCloseWarningDialog">取消</el-button>
...@@ -701,4 +706,13 @@ const { ...@@ -701,4 +706,13 @@ const {
} }
} }
} }
.no-el-label {
:deep(.el-form-item__content) {
text-align: left;
margin-left: 10px !important;
.el-checkbox__label {
line-height: 18px;
}
}
}
</style> </style>
...@@ -63,11 +63,11 @@ const labelData = [ ...@@ -63,11 +63,11 @@ const labelData = [
], ],
[ [
{ {
label: "预警对象", label: "预警分类",
prop: "warning_target", prop: "warning_target",
}, },
{ {
label: "预警分类", label: "预警对象",
prop: "warning_type", prop: "warning_type",
}, },
], ],
......
...@@ -169,11 +169,11 @@ const state = reactive({ ...@@ -169,11 +169,11 @@ const state = reactive({
width: 200, width: 200,
}, },
{ {
label: "预警对象", label: "预警分类",
prop: "warning_object", prop: "warning_object",
}, },
{ {
label: "预警分类", label: "预警对象",
prop: "warning_type_name", prop: "warning_type_name",
}, },
{ {
......
...@@ -28,20 +28,39 @@ ...@@ -28,20 +28,39 @@
<div class="add-form-item"> <div class="add-form-item">
<div class="duration"> <div class="duration">
<el-form-item label="持续时间" prop="time"> <el-form-item label="持续时间" prop="time">
<el-input v-model="state.form.time" placeholder="请输入持续时间" @input="inputNum">
<template #prepend>
<span>当预警持续</span> <span>当预警持续</span>
<el-input v-model="state.form.time" placeholder="请输入持续时间" @input="inputNum"></el-input> </template>
</el-form-item> <template #append>
<el-form-item label="" prop="time" class="no-el-label">
<el-select v-model="state.form.unit" placeholder="请选择"> <el-select v-model="state.form.unit" placeholder="请选择">
<el-option v-for="(value, key) in unitOptions" :key="key" :label="value.label" :value="key"> </el-option> <el-option v-for="(value, key) in unitOptions" :key="key" :label="value.label" :value="key">
</el-option>
</el-select> </el-select>
<span>时产生报警</span> </template>
</el-input>
<span class="duration-append">
<span> 时产生报警 </span>
<el-popover
:width="300"
title=""
content="大于等于0的正整数,等于0时代表直接报警"
trigger="hover"
placement="top-start">
<template #reference>
<bg-icon
style="font-size: 12px; color: #a9b1c7; margin-left: 8px; vertical-align: middle"
icon="#bg-ic-s-circle-tips"></bg-icon>
</template>
</el-popover>
</span>
</el-form-item> </el-form-item>
</div> </div>
<el-form-item label="检查周期" prop="inspection_cycle"> <el-form-item label="检查周期" prop="inspection_cycle">
<el-select style="flex: 1" v-model="state.form.inspection_cycle" placeholder="请选择"> <el-select class="cycle-select" style="flex: 1" v-model="state.form.inspection_cycle" placeholder="请选择">
<el-option v-for="item in inspectionCycleOptions" :key="item" :label="item" :value="item"> </el-option> <el-option v-for="item in inspectionCycleOptions" :key="item" :label="item" :value="item"> </el-option>
</el-select> </el-select>
<div class="cycle-unit">分钟</div>
</el-form-item> </el-form-item>
</div> </div>
<gap-title :hasLine="true" title="预警工单推送"></gap-title> <gap-title :hasLine="true" title="预警工单推送"></gap-title>
...@@ -205,25 +224,37 @@ defineExpose({ ...@@ -205,25 +224,37 @@ defineExpose({
} }
} }
.duration { .duration {
flex: 1;
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; :deep(.el-form-item) {
:deep(.el-form-item__content) { flex: 1;
display: flex; .el-input {
align-items: center; margin-right: 8px;
gap: 8px;
> .el-input {
flex: 1; flex: 1;
width: 80px;
} }
.el-input-group__prepend {
width: 102px;
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
} }
.no-el-label { .el-input-group__append {
:deep(.el-form-item__content) {
.el-select {
width: 80px; width: 80px;
border-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
} }
} }
} // :deep(.el-form-item__content) {
// display: flex;
// align-items: center;
// gap: 8px;
// > .el-input {
// flex: 1;
// width: 80px;
// }
// }
} }
:deep(.el-switch__inner) { :deep(.el-switch__inner) {
.is-hide { .is-hide {
...@@ -235,6 +266,26 @@ defineExpose({ ...@@ -235,6 +266,26 @@ defineExpose({
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
} }
.duration-append {
display: flex;
align-items: center;
color: #404a62;
}
.cycle-unit {
width: 60px;
height: 36px;
background-color: #f7f7f9;
border-radius: 0px 4px 4px 0px;
border: solid 1px #dadee7;
text-align: center;
border-left: 0;
}
.cycle-select {
:deep(.el-input__wrapper) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}
} }
} }
.no-el-label { .no-el-label {
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
<el-form-item label="预警对象" prop="warn_target"> <el-form-item label="预警对象" prop="warn_target">
<el-input <el-input
v-model="state.form.warn_target" v-model="state.form.warn_target"
placeholder="请输入" placeholder="请输入预警对象"
:disabled="isEdit" :disabled="isEdit"
:maxlength="20" :maxlength="20"
show-word-limit show-word-limit
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<el-form-item label="预警分类" prop="warn_type"> <el-form-item label="预警分类" prop="warn_type">
<el-input <el-input
v-model="state.form.warn_type" v-model="state.form.warn_type"
placeholder="请输入" placeholder="请输入预警分类"
:disabled="isEdit" :disabled="isEdit"
clearable clearable
:maxlength="20" :maxlength="20"
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
<el-form-item label="预警指标" prop="warn_indicator"> <el-form-item label="预警指标" prop="warn_indicator">
<el-input <el-input
v-model="state.form.warn_indicator" v-model="state.form.warn_indicator"
placeholder="请输入" placeholder="请输入预警指标"
:disabled="isEdit" :disabled="isEdit"
:maxlength="30" :maxlength="30"
show-word-limit show-word-limit
...@@ -97,7 +97,7 @@ ...@@ -97,7 +97,7 @@
<el-select <el-select
style="flex: 1" style="flex: 1"
v-model="state.form.ruleRows[$index].risk_level" v-model="state.form.ruleRows[$index].risk_level"
placeholder="请选择"> placeholder="请选择风险程度">
<el-option <el-option
v-for="item in riskLevelOptions($index)" v-for="item in riskLevelOptions($index)"
:key="item.id" :key="item.id"
...@@ -175,16 +175,15 @@ const state = reactive({ ...@@ -175,16 +175,15 @@ const state = reactive({
ruleRows: [], ruleRows: [],
}, },
rules: { rules: {
warn_target: [{ required: true, message: "请输入", trigger: "blur" }], warn_target: [{ required: true, message: "请输入预警对象", trigger: "blur" }],
warn_type: [{ required: true, message: "请输入", trigger: "blur" }], warn_type: [{ required: true, message: "请输入预警分类", trigger: "blur" }],
warn_indicator: [{ validator: validateWarnIndex, trigger: "blur" }], warn_indicator: [{ validator: validateWarnIndex, trigger: "blur" }],
indicator_expression: [{ required: true, message: "请输入", trigger: "blur" }], indicator_expression: [{ required: true, message: "请输入预警指标", trigger: "blur" }],
rule_type: [{ required: true, message: "请选择", trigger: "change" }],
}, },
tableRules: { tableRules: {
from: [{ required: true, message: "请输入", trigger: "blur" }], from: [{ required: true, message: "请输入", trigger: "blur" }],
to: [{ required: true, message: "请输入", trigger: "blur" }], to: [{ required: true, message: "请输入", trigger: "blur" }],
risk_level: [{ required: true, message: "请选择", trigger: "change" }], risk_level: [{ required: true, message: "请选择风险程度", trigger: "change" }],
}, },
}); });
const changeWarnCustomTarget = () => {}; const changeWarnCustomTarget = () => {};
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
style="flex: 1" style="flex: 1"
v-model.number="state.form.ruleRows[$index].from" v-model.number="state.form.ruleRows[$index].from"
placeholder="请输入" placeholder="请输入"
@input="changeWarningThresholdFrom($index)"> @input="inputNum($index, 'from')"
<template v-if="state.form.rule_type != 'empty'" #append>ms</template> @blur="changeWarningThresholdFrom($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit
}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<span class="to">-</span> <span class="to">-</span>
...@@ -32,8 +35,11 @@ ...@@ -32,8 +35,11 @@
v-model.number="state.form.ruleRows[$index].to" v-model.number="state.form.ruleRows[$index].to"
placeholder="请输入" placeholder="请输入"
clearable clearable
@input="changeWarningThresholdTo($index)"> @input="inputNum($index, 'to')"
<template v-if="state.form.rule_type != 'empty'" #append>ms</template> @blur="changeWarningThresholdTo($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit
}}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
</div> </div>
...@@ -77,13 +83,62 @@ ...@@ -77,13 +83,62 @@
<script setup> <script setup>
import { computed, reactive, ref, watch } from "vue"; import { computed, reactive, ref, watch } from "vue";
import gapTitle from "@/components/gap-title.vue"; import gapTitle from "@/components/gap-title.vue";
import { ElMessage } from "element-plus";
const props = defineProps({ const props = defineProps({
form: { form: {
type: Object, type: Object,
default: null, default: null,
}, },
rule_type: {
type: String,
default: "1",
},
}); });
const ruleTypeOptions = {
empty: {
label: "",
},
1: {
label: "百分比范围",
unit: "%",
limit: {
down: 0,
up: 100,
},
},
2: {
label: "毫秒范围",
unit: "ms",
limit: {
down: 0,
up: "",
},
},
3: {
label: "秒范围",
unit: "s",
limit: {
down: 0,
up: "",
},
},
4: {
label: "个范围",
unit: "",
limit: {
down: 0,
up: "",
},
},
5: {
label: "温度范围",
unit: "",
limit: {
down: "",
up: "",
},
},
};
const state = reactive({ const state = reactive({
form: { form: {
ruleRows: [], ruleRows: [],
...@@ -160,11 +215,26 @@ const setLimits = (index) => { ...@@ -160,11 +215,26 @@ const setLimits = (index) => {
}) || [] }) || []
); );
}; };
const limit = computed(() => {
return (
ruleTypeOptions[props.rule_type].limit || {
down: "",
up: "",
}
);
});
const changeWarningThresholdFrom = (index) => { const changeWarningThresholdFrom = (index) => {
let { down, up } = limit.value; let { down, up } = limit.value;
if (down === "") return; if (down === "") return;
let { from, to } = state.form.ruleRows[index]; let { from, to } = state.form.ruleRows[index];
if (+from > +up || (index == 0 && +from < +down) || +from > +to) { if (+from > +up || (index == 0 && +from < +down) || (to != "" && from > +to)) {
if (+from < +down) {
ElMessage.error(`下限不能小于${down}`);
} else if (+from > +up) {
ElMessage.error(`上限不能超过${up}`);
} else {
ElMessage.error(`下限不能大于上限`);
}
state.form.ruleRows[index].from = ""; state.form.ruleRows[index].from = "";
return; return;
} }
...@@ -177,14 +247,25 @@ const changeWarningThresholdFrom = (index) => { ...@@ -177,14 +247,25 @@ const changeWarningThresholdFrom = (index) => {
} }
}); });
} catch (e) { } catch (e) {
ElMessage.error(`该范围已被设置`);
state.form.ruleRows[index].from = ""; state.form.ruleRows[index].from = "";
} }
}; };
const inputNum = (index, key) => {
state.form.ruleRows[index][key] = state.form.ruleRows[index][key].replace(/[^\d]/g, "");
};
const changeWarningThresholdTo = (index) => { const changeWarningThresholdTo = (index) => {
let { down, up } = limit.value; let { down, up } = limit.value;
if (up === "") return; if (up === "") return;
let { from, to } = state.form.ruleRows[index]; let { from, to } = state.form.ruleRows[index];
if ((index == 0 && +to > +up) || +to < +down || +from > +to) { if ((index == 0 && +to > +up) || +to < +down || (from != "" && +from > +to)) {
if (+to > +up) {
ElMessage.error(`上限不能超过${up}`);
} else if (+to < +down) {
ElMessage.error(`下限不能小于${down}`);
} else {
ElMessage.error(`上限不能小于下限`);
}
state.form.ruleRows[index].to = ""; state.form.ruleRows[index].to = "";
return; return;
} }
...@@ -197,6 +278,7 @@ const changeWarningThresholdTo = (index) => { ...@@ -197,6 +278,7 @@ const changeWarningThresholdTo = (index) => {
} }
}); });
} catch (e) { } catch (e) {
ElMessage.error(`该范围已被设置`);
state.form.ruleRows[index].to = ""; state.form.ruleRows[index].to = "";
} }
}; };
......
...@@ -52,7 +52,7 @@ ...@@ -52,7 +52,7 @@
<el-input <el-input
class="warn-scpoe-input-value" class="warn-scpoe-input-value"
v-model="state.form.warning_scpoe_form[index].value" v-model="state.form.warning_scpoe_form[index].value"
placeholder="请输入" :placeholder="`请输入${item.chinese_name}`"
v-if="!showSelect.includes(item.select)" v-if="!showSelect.includes(item.select)"
:disabled="item.select == 1"> :disabled="item.select == 1">
</el-input> </el-input>
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
class="warn-scpoe-input-value" class="warn-scpoe-input-value"
v-else v-else
v-model="item.value" v-model="item.value"
placeholder="请选择" :placeholder="`请选择${item.chinese_name}`"
filterable filterable
:loading="item.loading" :loading="item.loading"
remote remote
...@@ -83,7 +83,7 @@ ...@@ -83,7 +83,7 @@
</el-option> </el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<Gateway v-else ref="warn_type_com" /> <Gateway v-else ref="warn_type_com" :rule_type="alert_rule_type" />
</div> </div>
</div> </div>
</div> </div>
...@@ -370,9 +370,9 @@ defineExpose({ ...@@ -370,9 +370,9 @@ defineExpose({
width: 100%; width: 100%;
padding-left: 8px; padding-left: 8px;
.warning-scope-main { .warning-scope-main {
display: grid; // display: grid;
grid-template-columns: 1fr 1fr; // grid-template-columns: 1fr 1fr;
grid-column-gap: 16px; // grid-column-gap: 16px;
:deep(.el-input-group__prepend) { :deep(.el-input-group__prepend) {
border-radius: 4px; border-radius: 4px;
border-top-right-radius: 0; border-top-right-radius: 0;
...@@ -385,9 +385,13 @@ defineExpose({ ...@@ -385,9 +385,13 @@ defineExpose({
.warn-scpoe-select { .warn-scpoe-select {
width: 114px !important; width: 114px !important;
:deep(.el-input__wrapper) { :deep(.el-input__wrapper) {
background-color: #2b4695;
border-radius: 4px; border-radius: 4px;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
.el-input__inner {
color: #fff;
}
} }
} }
.warn-scpoe-input-item { .warn-scpoe-input-item {
......
...@@ -905,9 +905,9 @@ markdown-it@^13.0.1: ...@@ -905,9 +905,9 @@ markdown-it@^13.0.1:
mdurl "^1.0.1" mdurl "^1.0.1"
uc.micro "^1.0.5" uc.micro "^1.0.5"
mavon-editor@^3.0.0: mavon-editor@^3.0.1:
version "3.0.1" version "3.0.1"
resolved "https://registry.npmmirror.com/mavon-editor/-/mavon-editor-3.0.1.tgz" resolved "https://registry.yarnpkg.com/mavon-editor/-/mavon-editor-3.0.1.tgz#0c2660569ded5b29e59d0e429af61eb618783a90"
integrity sha512-973cYCwv+AB+fcecsU6Ua6UXATxDMaY0Q7QzKQ/GmRW1sg+3DolZDnCGXth7XHDgrmqKTO57N42fVYujt0wfFw== integrity sha512-973cYCwv+AB+fcecsU6Ua6UXATxDMaY0Q7QzKQ/GmRW1sg+3DolZDnCGXth7XHDgrmqKTO57N42fVYujt0wfFw==
dependencies: dependencies:
xss "^1.0.10" xss "^1.0.10"
...@@ -1083,6 +1083,11 @@ ssr-window@^3.0.0-alpha.1: ...@@ -1083,6 +1083,11 @@ ssr-window@^3.0.0-alpha.1:
resolved "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz" resolved "https://registry.npmmirror.com/ssr-window/-/ssr-window-3.0.0.tgz"
integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA== integrity sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==
string-format@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/string-format/-/string-format-2.0.0.tgz#f2df2e7097440d3b65de31b6d40d54c96eaffb9b"
integrity sha512-bbEs3scLeYNXLecRRuk6uJxdXUSj6le/8rNPHChIJTn2V79aXVTR1EH2OH5zLKKoz0V02fOUKZZcw01pLUShZA==
supports-preserve-symlinks-flag@^1.0.0: supports-preserve-symlinks-flag@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
...@@ -1161,6 +1166,11 @@ vue-demi@*: ...@@ -1161,6 +1166,11 @@ vue-demi@*:
resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz" resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.13.11.tgz"
integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A== integrity sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==
vue-demi@^0.14.5:
version "0.14.5"
resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.14.5.tgz#676d0463d1a1266d5ab5cba932e043d8f5f2fbd9"
integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA==
vue-i18n@^9.1.7: vue-i18n@^9.1.7:
version "9.1.10" version "9.1.10"
resolved "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.1.10.tgz" resolved "https://registry.npmmirror.com/vue-i18n/-/vue-i18n-9.1.10.tgz"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment