Commit c1620424 authored by 张耀's avatar 张耀

feat:

预警规则设置接口对接
parent 0629c24b
// 通知方式 // 通知方式
export const METHODS = { export const METHODS = {
1: '钉钉', dingtalk: '钉钉',
2: '短信' sms: '短信'
} }
// 可以新增的数量 // 可以新增的数量
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
:model="state.form" :model="state.form"
ref="form_ref" ref="form_ref"
:rules="state.rules" :rules="state.rules"
label-width="110px" :label-width="labelWidth"
:disabled="disabled" :disabled="disabled"
style="width: 100%"> style="width: 100%">
<el-form-item :label="methodLabel || '通知方式'" prop="method"> <el-form-item :label="methodLabel || '通知方式'" prop="method">
...@@ -97,6 +97,10 @@ const props = defineProps({ ...@@ -97,6 +97,10 @@ const props = defineProps({
type: Object, type: Object,
default: () => ({}), default: () => ({}),
}, },
labelWidth: {
type: String,
default: "110px",
},
}); });
const form_ref = ref(null); const form_ref = ref(null);
// 表单数据 // 表单数据
......
...@@ -129,13 +129,42 @@ const rule_label = [ ...@@ -129,13 +129,42 @@ const rule_label = [
], ],
]; ];
const rule_data = ref({}); const rule_data = ref({});
const ruleTypeOptions = { const ruleTypeOptions = ref({});
empty: "", const getRuleTypeOptions = () => {
1: "百分比范围", let arr = [
2: "毫秒范围", {
3: "秒范围", id: "empty",
4: "个范围", label: "",
5: "温度范围", },
{
id: "1",
label: "百分比范围",
unit: "%",
},
{
id: "2",
label: "毫秒范围",
unit: "ms",
},
{
id: "3",
label: "秒范围",
unit: "s",
},
{
id: "4",
label: "个范围",
unit: "",
},
{
id: "5",
label: "温度范围",
unit: "",
},
];
arr.forEach((e) => {
ruleTypeOptions.value[e.id] = e.label;
});
}; };
const advanced_label = [ const advanced_label = [
[ [
...@@ -225,6 +254,7 @@ const getInfoData = () => { ...@@ -225,6 +254,7 @@ const getInfoData = () => {
}); });
}; };
onBeforeMount(() => { onBeforeMount(() => {
getRuleTypeOptions();
getInfoData(); getInfoData();
}); });
</script> </script>
......
...@@ -211,8 +211,7 @@ const selectable = (row, index) => { ...@@ -211,8 +211,7 @@ const selectable = (row, index) => {
}; };
const getTableRows = () => { const getTableRows = () => {
let params = { ...state.filter, class_id: node.value.data.class_id }; let params = { ...state.filter, class_id: node.value.data.class_id };
// axios.get("/v1/api/metric_config/list", { params }).then((res) => { axios.get("/v1/api/metric_config/list", { params }).then((res) => {
axios.get("/v1/api/metric_config/list").then((res) => {
if (res.data.code == 200) { if (res.data.code == 200) {
state.tableRows = state.tableRows =
res.data.data?.list?.map((e) => { res.data.data?.list?.map((e) => {
......
...@@ -70,14 +70,40 @@ const props = defineProps({ ...@@ -70,14 +70,40 @@ const props = defineProps({
// 预警规则类型下拉 // 预警规则类型下拉
const ruleTypeOptions = ref({}); const ruleTypeOptions = ref({});
const getRuleTypeOptions = () => { const getRuleTypeOptions = () => {
ruleTypeOptions.value = { let arr = [
empty: "", {
1: "百分比范围", id: "empty",
2: "毫秒范围", label: "",
3: "秒范围", },
4: "个范围", {
5: "温度范围", id: "1",
}; label: "百分比范围",
unit: "%",
},
{
id: "2",
label: "毫秒范围",
unit: "ms",
},
{
id: "3",
label: "秒范围",
unit: "s",
},
{
id: "4",
label: "个范围",
unit: "",
},
{
id: "5",
label: "温度范围",
unit: "",
},
];
arr.forEach((e) => {
ruleTypeOptions.value[e.id] = e.label;
});
}; };
// 当前是否是编辑 // 当前是否是编辑
const isEdit = computed(() => !!props.row); const isEdit = computed(() => !!props.row);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
</div> </div>
<div class="add-btns"> <div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button> <el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="Save">保存</el-button> <el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div> </div>
</div> </div>
</div> </div>
...@@ -18,15 +18,20 @@ import { ref } from "vue"; ...@@ -18,15 +18,20 @@ import { ref } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue"; import addForm from "../modules/add-form.vue";
import { ElMessage } from "element-plus";
import { Save } from "../modules/interface.js";
const router = useRouter(); const router = useRouter();
const Cancle = () => { const Cancle = () => {
router.go(-1); router.go(-1);
}; };
const add_form = ref(null); const add_form = ref(null);
const Save = async () => { const SaveSubmit = async () => {
let res = await add_form.value.Submit(); let res = await add_form.value.Submit();
if (!res) return; if (!res) return;
console.log("res: ", res); console.log("res: ", res);
Save(res, {}, () => {
Cancle();
});
}; };
</script> </script>
......
...@@ -13,10 +13,18 @@ ...@@ -13,10 +13,18 @@
</template> </template>
</Info> </Info>
</div> </div>
<div class="warn-scope" v-if="detection_type == 1">
<gap-title :hasLine="true" title="预警范围"></gap-title> <gap-title :hasLine="true" title="预警范围"></gap-title>
<div class="info"> <div class="info">
<Info :labelData="warning_scope_label" :valueData="watning_scope_data"> </Info> <Info :labelData="warning_scope_label" :valueData="watning_scope_data"> </Info>
</div> </div>
</div>
<div class="warn-scope" v-else>
<gap-title :hasLine="true" title="指标表达式"></gap-title>
<div class="indicator-expression">
<bg-code-editor v-model="indicator_expression" :disabled="true"></bg-code-editor>
</div>
</div>
<gap-title :hasLine="true" title="预警规则"></gap-title> <gap-title :hasLine="true" title="预警规则"></gap-title>
<div class="info"> <div class="info">
<bg-table border ref="ruletable" :headers="ruleHeaders" :rows="ruleRows" height="100%"> </bg-table> <bg-table border ref="ruletable" :headers="ruleHeaders" :rows="ruleRows" height="100%"> </bg-table>
...@@ -29,7 +37,7 @@ ...@@ -29,7 +37,7 @@
<div class="info"> <div class="info">
<Info :labelData="ticket_push_label" :valueData="ticket_push_data"> <Info :labelData="ticket_push_label" :valueData="ticket_push_data">
<template #notification_method="{ valueData }"> <template #notification_method="{ valueData }">
<span>{{ valueData.notification_method.map((e) => METHODS[e]).join("") }}</span> <span>{{ valueData.notification_method?.map((e) => METHODS[e]).join("") || "" }}</span>
</template> </template>
</Info> </Info>
<div class="push-lists"> <div class="push-lists">
...@@ -42,13 +50,34 @@ ...@@ -42,13 +50,34 @@
</template> </template>
<script setup> <script setup>
import { ref, onBeforeMount, computed } from "vue";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { useRoute } from "vue-router";
import gapTitle from "@/components/gap-title.vue"; import gapTitle from "@/components/gap-title.vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import Info from "@/components/warn-detail/info.vue"; import Info from "@/components/warn-detail/info.vue";
import { METHODS } from "@/components/manual-distribution/env.js"; import { METHODS } from "@/components/manual-distribution/env.js";
const STATUS_OBJ = { const route = useRoute();
enabled: "启用", const { id } = route.query;
disabled: "禁用", const STATUS_OBJ = ["禁用", "启用"];
const ruleTypeOptions = ref({});
const selectRule = {
"=": "等于",
"!=": "不等于",
"=~": "正则匹配",
"!~": "正则不匹配",
};
const riskLevelOptions = {
4: "重大风险",
3: "较大风险",
2: "一般风险",
1: "低风险",
};
const unitOptions = {
s: "",
m: "分钟",
h: "小时",
}; };
const labelData = [ const labelData = [
[ [
...@@ -92,34 +121,9 @@ const labelData = [ ...@@ -92,34 +121,9 @@ const labelData = [
}, },
], ],
]; ];
const info = { const info = ref({});
warning_rule_name: "服务中断推送规则1", const warning_scope_label = ref([]);
status: "enabled", const watning_scope_data = ref({});
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",
};
const warning_scope_label = [
[
{
prop: "colony",
label: "集群",
},
],
[
{
prop: "core_com",
label: "核心组件",
},
],
];
const watning_scope_data = {
colony: "等于 default",
core_com: "等于 kube-apiserver/kube-apiserver2/kube-apiserver3",
};
const advanced_label = [ const advanced_label = [
[ [
{ {
...@@ -134,10 +138,7 @@ const advanced_label = [ ...@@ -134,10 +138,7 @@ const advanced_label = [
}, },
], ],
]; ];
const advanced_data = { const advanced_data = ref({});
duration: "直接产生预警",
inspection_cycle: "1分钟",
};
const ticket_push_label = [ const ticket_push_label = [
[ [
{ {
...@@ -158,51 +159,135 @@ const ticket_push_label = [ ...@@ -158,51 +159,135 @@ const ticket_push_label = [
}, },
], ],
]; ];
const ticket_push_data = { const ticket_push_data = ref({});
notification_method: ["1", "2"], const ruleHeaders = ref([
push_num: "10次",
push_frequency: "60分钟",
};
const ruleHeaders = [
{
prop: "warning_threshold",
label: "预警阈值",
},
{ {
prop: "risk_level", prop: "risk_level",
label: "风险程度", label: "风险程度",
}, },
]; ]);
const ruleRows = [ const ruleRows = ref([]);
const pushHeaders = [
{ {
warning_threshold: "12% - 50% ", prop: "system_account",
risk_level: "较大风险", label: "账号",
}, },
{ {
warning_threshold: "50% - 100% ", prop: "user_name",
risk_level: "重大风险", label: "姓名",
},
{
prop: "phone",
label: "联系方式",
}, },
]; ];
const pushHeaders = [ const pushRows = ref([]);
const detection_type = ref(1);
const indicator_expression = ref("");
const getInfoData = () => {
axios
.get("/v1/api/alert_rules", {
params: {
id: id,
},
})
.then((res) => {
if (res.data.code == 200) {
const { data } = res.data;
detection_type.value = data.detection_type;
indicator_expression.value = data.expr;
info.value = {
warning_rule_name: data.metric_name,
status: data.is_enabled,
warning_target: data.class_parent_name,
warning_type: data.class_name,
warning_index: data.metric_config_name,
create_by: data.created_by,
create_time: data.created_at,
update_time: data.updated_at,
};
data.alert_range.forEach((e) => {
warning_scope_label.value.push([
{
prop: e.name,
label: e.chinese_name || e.name,
},
]);
watning_scope_data.value[e.name] = e.value == ".*" ? "全部" : `${selectRule[e.compare]} ${e.value}`;
});
let isEmpty = !data.alert_rule_type || data.alert_rule_type == "empty";
if (!isEmpty) {
ruleHeaders.value = [
{ {
prop: "warning_threshold", prop: "warning_threshold",
label: "预警阈值", label: "预警阈值",
}, },
...ruleHeaders.value,
];
}
ruleRows.value = data.alert_condition.map((e) => {
return {
warning_threshold: `${e.thresholds_min}${ruleTypeOptions.value[data.alert_rule_type].unit} - ${
e.thresholds_max
}${ruleTypeOptions.value[data.alert_rule_type].unit}`,
risk_level: riskLevelOptions[e.risk_level],
};
});
advanced_data.value = {
duration: data.duration == 0 ? "直接产生预警" : data.duration + unitOptions[data.duration_unit],
inspection_cycle: data.check_period + "分钟",
};
ticket_push_data.value = {
notification_method: data.notify_method,
push_num: data.notify_push_count + "",
push_frequency: data.notify_push_frequency + "分钟",
};
pushRows.value = data.notify_recipients;
} else {
ElMessage.error(res.data.data);
}
});
};
const getRuleTypeOptions = () => {
let arr = [
{ {
prop: "risk_level", id: "empty",
label: "风险程度", label: "",
}, },
];
const pushRows = [
{ {
warning_threshold: "12% - 50% ", id: "1",
risk_level: "较大风险", label: "百分比范围",
unit: "%",
}, },
{ {
warning_threshold: "50% - 100% ", id: "2",
risk_level: "重大风险", label: "毫秒范围",
unit: "ms",
}, },
]; {
id: "3",
label: "秒范围",
unit: "s",
},
{
id: "4",
label: "个范围",
unit: "",
},
{
id: "5",
label: "温度范围",
unit: "",
},
];
arr.forEach((e) => {
ruleTypeOptions.value[e.id] = e;
});
getInfoData();
};
onBeforeMount(() => {
getRuleTypeOptions();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
...@@ -221,6 +306,16 @@ const pushRows = [ ...@@ -221,6 +306,16 @@ const pushRows = [
:deep(.gap-title) { :deep(.gap-title) {
margin-bottom: 16px; margin-bottom: 16px;
} }
.warn-scope {
margin-bottom: 24px;
.indicator-expression {
height: 300px;
width: 100%;
:deep(.vue-ace-editor) {
margin-top: 0;
}
}
}
.info { .info {
max-width: 1072px; max-width: 1072px;
width: 100%; width: 100%;
...@@ -241,8 +336,8 @@ const pushRows = [ ...@@ -241,8 +336,8 @@ const pushRows = [
border-radius: 50%; border-radius: 50%;
margin-right: 8px; margin-right: 8px;
$statusObj: ( $statusObj: (
enabled: #48ad97, 1: #48ad97,
disabled: #9e9e9e, 0: #9e9e9e,
); );
@each $status, $color in $statusObj { @each $status, $color in $statusObj {
&-#{$status} { &-#{$status} {
......
...@@ -7,181 +7,155 @@ ...@@ -7,181 +7,155 @@
</div> </div>
<div class="add-btns"> <div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button> <el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="Save">保存</el-button> <el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref, onBeforeMount } from "vue";
import { useRouter } from "vue-router"; import { useRouter, useRoute } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue"; import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue"; import addForm from "../modules/add-form.vue";
// const infoData = ref({ import axios from "@/request/http.js";
// id: 1, import { ElMessage } from "element-plus";
// name: "11", import { Save } from "../modules/interface.js";
// type_key: "static", const infoData = ref({});
// duration: 1,
// time: 10,
// inspection_cycle: 1,
// push_num: 1,
// push_frequency: 60,
// enabled: true,
// type_com_ref: {
// warn_type: "colony",
// warn_indicator: "1",
// warn_target: "1",
// warn_type_com: {
// value1: "22",
// value1_select: "3",
// value2: "33",
// value2_select: "2",
// risk_level: 1,
// },
// },
// manual_distribution_form: {
// method: ["1", "2"],
// lists: [
// {
// user_id: 2,
// user_name: 22,
// phone: 13000000002,
// },
// {
// user_id: 3,
// user_name: 33,
// phone: 13000000003,
// },
// ],
// },
// });
const infoData = ref({
name: "11",
type_key: "static",
duration: 1,
time: 10,
inspection_cycle: 1,
push_num: 1,
push_frequency: 60,
enabled: true,
type_com_ref: {
warn_type: "gateway",
warn_indicator: "1",
warn_target: "1",
warn_type_com: {
ruleRows: [
{
from: "22",
to: "33",
risk_level: 1,
},
{
from: "44",
to: "55",
risk_level: 2,
},
],
},
},
manual_distribution_form: {
method: ["1"],
lists: [
{
user_id: 1,
user_name: 11,
phone: 13000000001,
},
],
},
});
// const infoData = ref({
// id: 1,
// name: "11",
// type_key: "static",
// duration: 1,
// time: 10,
// inspection_cycle: 1,
// push_num: 1,
// push_frequency: 60,
// enabled: true,
// type_com_ref: {
// warn_type: "colony",
// warn_indicator: "1",
// warn_target: "1",
// warn_type_com: {
// value1: "22",
// value1_select: "3",
// value2: "33",
// value2_select: "2",
// risk_level: 1,
// },
// },
// manual_distribution_form: {
// method: ["1", "2"],
// lists: [
// {
// user_id: 2,
// user_name: 22,
// phone: 13000000002,
// },
// {
// user_id: 3,
// user_name: 33,
// phone: 13000000003,
// },
// ],
// },
// });
// const infoData = ref({
// name: "11",
// type_key: "custom",
// duration: 1,
// time: 10,
// inspection_cycle: 1,
// push_num: 1,
// push_frequency: 60,
// enabled: true,
// type_com_ref: {
// warn_target: "22",
// warn_type: "33",
// warn_indicator: "44",
// indicator_expression: "55\n66\n77",
// rule_type: "1",
// ruleRows: [
// {
// from: "88",
// to: "99",
// risk_level: 1,
// },
// ],
// },
// manual_distribution_form: {
// method: ["1", "2"],
// lists: [
// {
// user_id: 1,
// user_name: 11,
// phone: 13000000001,
// },
// {
// user_id: 2,
// user_name: 22,
// phone: 13000000002,
// },
// ],
// },
// });
const router = useRouter(); const router = useRouter();
const route = useRoute();
const { id } = route.query;
const Cancle = () => { const Cancle = () => {
router.go(-1); router.go(-1);
}; };
const add_form = ref(null); const add_form = ref(null);
const Save = async () => { const SaveSubmit = async () => {
let res = await add_form.value.Submit(); let res = await add_form.value.Submit();
if (!res) return; if (!res) return;
console.log("res: ", res); console.log("res: ", res);
Save(res, { id }, () => {
Cancle();
});
};
const staticTypeOptions = ref([]);
const findTypeBySecond = (id) => {
return staticTypeOptions.value.find((e) => {
return e.children.find((e_c) => e_c.class_id == id);
});
};
const getInfoData = () => {
axios
.get("/v1/api/alert_rules", {
params: {
id: id,
},
})
.then((res) => {
if (res.data.code == 200) {
const { data } = res.data;
console.log("data: ", data);
const isEmpty = !data.alert_rule_type || data.alert_rule_type == "empty";
let type_json = {
1: () => {
let obj = {
key: "static",
type_com_ref: {
warn_type: data.class_id,
warn_indicator: data.metric_config_id,
warn_target: findTypeBySecond(data.class_id)?.class_id || "",
rule_type: data.alert_rule_type,
},
};
// if (isEmpty) {
// obj.type_com_ref.risk_level = data.alert_condition[0].risk_level;
// } else {
obj.type_com_ref.warning_scpoe_form =
data.alert_range?.map((e) => {
return {
...e,
select: e.compare,
options: [],
};
}) || [];
obj.type_com_ref.ruleRows =
data.alert_condition?.map((e) => {
return {
from: e.thresholds_min,
to: e.thresholds_max,
risk_level: e.risk_level,
};
}) || [];
// }
return obj;
},
2: () => {
let obj = {
key: "custom",
type_com_ref: {
warn_target: data.class_parent_name,
warn_type: data.class_name,
warn_indicator: data.metric_config_name,
indicator_expression: data.expr,
rule_type: data.alert_rule_type,
},
};
if (isEmpty) {
obj.type_com_ref.risk_level = data.alert_condition[0].risk_level;
} else {
obj.type_com_ref.ruleRows =
data.alert_condition?.map((e) => {
return {
from: e.thresholds_min,
to: e.thresholds_max,
risk_level: e.risk_level,
};
}) || [];
}
return obj;
},
};
let d = type_json[`${data.detection_type}`]();
infoData.value = {
name: data.metric_name,
type_key: d.key,
unit: data.duration_unit,
time: data.duration,
inspection_cycle: data.check_period,
push_num: data.notify_push_count,
push_frequency: data.notify_push_frequency,
enabled: data.is_enabled ? 1 : 2,
type_com_ref: d.type_com_ref,
manual_distribution_form: {
method: data.notify_method,
lists:
data.notify_recipients?.map((e) => {
return {
user_id: e.system_account,
user_name: e.user_name,
phone: e.phone,
};
}) || [],
},
};
} else {
ElMessage.error(res.data.data);
}
});
}; };
const getStaticTypeOptions = () => {
axios.get("/v1/api/alert_class/tree").then(async (res) => {
if (res.data.code == 200) {
staticTypeOptions.value = res.data.data;
getInfoData();
} else {
ElMessage.error(res.data.msg);
}
});
};
onBeforeMount(() => {
getStaticTypeOptions();
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
......
<template> <template>
<div class="add-form"> <div class="add-form">
<el-form :model="state.form" ref="form_ref" :rules="state.rules" label-width="110px"> <el-form :model="state.form" ref="form_ref" :rules="state.rules" label-width="120px">
<div class="add-form-item"> <div class="add-form-item">
<el-form-item label="预警规则名称" prop="name"> <el-form-item label="预警规则名称" prop="name">
<el-input v-model="state.form.name" :disabled="isEdit" placeholder="请输入预警规则名称"></el-input> <el-input v-model="state.form.name" :disabled="isEdit" placeholder="请输入预警规则名称"></el-input>
...@@ -70,6 +70,7 @@ ...@@ -70,6 +70,7 @@
<ManualDistributionForm <ManualDistributionForm
ref="manual_distribution_form" ref="manual_distribution_form"
class="manual-distribution-form" class="manual-distribution-form"
labelWidth="120px"
:noElLabel="false" :noElLabel="false"
methodLabel="预警通知方式" methodLabel="预警通知方式"
:history="history" /> :history="history" />
......
<template>
<div class="container-cluster-form">
<el-form :model="state.form" ref="form_ref" :rules="state.rules" label-width="110px">
<gap-title :hasLine="true" title="预警范围"></gap-title>
<div class="container-cluster-form-item warning-scope-form-item">
<el-form-item :label="typeToTextJson[props.type][0]" prop="value1">
<el-input v-model="state.form.value1" placeholder="请输入">
<template #prepend>
<el-select class="rule-select" v-model="state.form.value1_select" style="width: 114px">
<el-option v-for="(value, key) in selectRule" :key="key" :label="value" :value="key" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item :label="typeToTextJson[props.type][1]" prop="value2">
<el-input v-model="state.form.value2" placeholder="请输入">
<template #prepend>
<el-select class="rule-select" v-model="state.form.value2_select" style="width: 114px">
<el-option v-for="(value, key) in selectRule" :key="key" :label="value" :value="key" />
</el-select>
</template>
</el-input>
</el-form-item>
</div>
<gap-title :hasLine="true" title="预警规则"></gap-title>
<div class="container-cluster-form-item">
<el-form-item label="风险程度" prop="risk_level">
<el-select style="flex: 1" v-model="state.form.risk_level" placeholder="请选择" filterable>
<el-option v-for="item in riskLevelOptions" :key="item.id" :label="item.name" :value="item.id"> </el-option>
</el-select>
</el-form-item>
</div>
</el-form>
</div>
</template>
<script setup>
import { reactive, ref, watch } from "vue";
import gapTitle from "@/components/gap-title.vue";
const props = defineProps({
type: {
type: String,
default: "",
},
form: {
type: Object,
default: null,
},
});
const typeToTextJson = {
colony: ["集群", "核心组件"],
node: ["集群", "节点"],
group: ["命名空间", "容器"],
};
const selectRule = ref({
1: "遍历",
2: "等于",
3: "不等于",
4: "正则匹配",
5: "正则不匹配",
});
const state = reactive({
form: {
value1: "",
value1_select: "1",
value2: "",
value2_select: "1",
risk_level: "",
},
rules: {
value1: [{ required: true, message: "请输入", trigger: "blur" }],
value2: [{ required: true, message: "请输入", trigger: "blur" }],
risk_level: [{ required: true, message: "请选择", trigger: "change" }],
},
});
const form_ref = ref(null);
watch(
() => props.type,
(n) => {
state.form.value1 = "";
state.form.value1_select = "1";
state.form.value2 = "";
state.form.value2_select = "1";
form_ref.value.clearValidate(["value1", "value2", "risk_level"]);
}
);
watch(
() => props.form,
(n) => {
if (!n) return;
state.form.value1 = n.value1;
state.form.value1_select = n.value1_select || "1";
state.form.value2 = n.value2;
state.form.value2_select = n.value2_select || "1";
state.form.risk_level = n.risk_level;
},
{
deep: true,
immediate: true,
}
);
const riskLevelOptions = ref([
{
id: 1,
name: "重大风险",
},
{
id: 2,
name: "较大风险",
},
{
id: 3,
name: "一般风险",
},
{
id: 4,
name: "低风险",
},
]);
const Submit = async () => {
let form_valid = await new Promise((resolve, reject) => {
form_ref.value.validate((res) => resolve(res));
});
return form_valid;
};
defineExpose({
Submit,
form: state.form,
form_ref,
});
</script>
<style lang="scss" scoped>
.container-cluster-form {
:deep(.gap-title) {
margin-bottom: 16px;
}
&-item {
max-width: 1080px;
width: 100%;
padding-left: 8px;
}
.warning-scope-form-item {
display: flex;
align-items: center;
:deep(.el-form-item) {
flex: 1;
.el-input-group__prepend {
border-radius: 4px !important;
border-top-right-radius: 0 !important;
border-bottom-right-radius: 0 !important;
overflow: hidden;
}
}
:deep(.el-input-group__prepend) {
background-color: #2b4695;
.el-input__wrapper {
box-shadow: 1px 0 0 0 #2b4695 !important;
&,
.el-input__inner {
color: #fff;
}
.el-input__wrapper {
color: #fff;
}
}
}
}
}
</style>
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
@input="inputNum($index, 'from')" @input="inputNum($index, 'from')"
@blur="changeWarningThresholdFrom($index)"> @blur="changeWarningThresholdFrom($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{ <template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit ruleTypeOptions[rule_type]?.unit || ""
}}</template> }}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
@input="inputNum($index, 'to')" @input="inputNum($index, 'to')"
@blur="changeWarningThresholdTo($index)"> @blur="changeWarningThresholdTo($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{ <template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit ruleTypeOptions[rule_type]?.unit || ""
}}</template> }}</template>
</el-input> </el-input>
</el-form-item> </el-form-item>
...@@ -81,7 +81,7 @@ ...@@ -81,7 +81,7 @@
</template> </template>
<script setup> <script setup>
import { computed, reactive, ref, watch } from "vue"; import { computed, nextTick, reactive, ref, watch } from "vue";
import gapTitle from "@/components/gap-title.vue"; import gapTitle from "@/components/gap-title.vue";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
const props = defineProps({ const props = defineProps({
...@@ -94,11 +94,15 @@ const props = defineProps({ ...@@ -94,11 +94,15 @@ const props = defineProps({
default: "1", default: "1",
}, },
}); });
const ruleTypeOptions = { const ruleTypeOptions = ref({});
empty: { const getRuleTypeOptions = async (cb) => {
let arr = [
{
id: "empty",
label: "", label: "",
}, },
1: { {
id: "1",
label: "百分比范围", label: "百分比范围",
unit: "%", unit: "%",
limit: { limit: {
...@@ -106,7 +110,8 @@ const ruleTypeOptions = { ...@@ -106,7 +110,8 @@ const ruleTypeOptions = {
up: 100, up: 100,
}, },
}, },
2: { {
id: "2",
label: "毫秒范围", label: "毫秒范围",
unit: "ms", unit: "ms",
limit: { limit: {
...@@ -114,7 +119,8 @@ const ruleTypeOptions = { ...@@ -114,7 +119,8 @@ const ruleTypeOptions = {
up: "", up: "",
}, },
}, },
3: { {
id: "3",
label: "秒范围", label: "秒范围",
unit: "s", unit: "s",
limit: { limit: {
...@@ -122,7 +128,8 @@ const ruleTypeOptions = { ...@@ -122,7 +128,8 @@ const ruleTypeOptions = {
up: "", up: "",
}, },
}, },
4: { {
id: "4",
label: "个范围", label: "个范围",
unit: "", unit: "",
limit: { limit: {
...@@ -130,7 +137,8 @@ const ruleTypeOptions = { ...@@ -130,7 +137,8 @@ const ruleTypeOptions = {
up: "", up: "",
}, },
}, },
5: { {
id: "5",
label: "温度范围", label: "温度范围",
unit: "", unit: "",
limit: { limit: {
...@@ -138,6 +146,12 @@ const ruleTypeOptions = { ...@@ -138,6 +146,12 @@ const ruleTypeOptions = {
up: "", up: "",
}, },
}, },
];
arr.forEach((e) => {
ruleTypeOptions.value[e.id] = e;
});
await nextTick();
cb && cb();
}; };
const state = reactive({ const state = reactive({
form: { form: {
...@@ -158,19 +172,19 @@ const Submit = async () => { ...@@ -158,19 +172,19 @@ const Submit = async () => {
}; };
const riskLevels = ref([ const riskLevels = ref([
{ {
id: 1, id: 4,
name: "重大风险", name: "重大风险",
}, },
{ {
id: 2, id: 3,
name: "较大风险", name: "较大风险",
}, },
{ {
id: 3, id: 2,
name: "一般风险", name: "一般风险",
}, },
{ {
id: 4, id: 1,
name: "低风险", name: "低风险",
}, },
]); ]);
...@@ -215,9 +229,13 @@ const setLimits = (index) => { ...@@ -215,9 +229,13 @@ const setLimits = (index) => {
}) || [] }) || []
); );
}; };
const rule_type = computed(() => {
// return props.rule_type
return "1";
});
const limit = computed(() => { const limit = computed(() => {
return ( return (
ruleTypeOptions[props.rule_type].limit || { ruleTypeOptions.value[rule_type.value].limit || {
down: "", down: "",
up: "", up: "",
} }
...@@ -227,7 +245,7 @@ const changeWarningThresholdFrom = (index) => { ...@@ -227,7 +245,7 @@ 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) || (to != "" && from > +to)) { if ((up != "" && +from > +up) || (index == 0 && +from < +down) || (to != "" && from > +to)) {
if (+from < +down) { if (+from < +down) {
ElMessage.error(`下限不能小于${down}`); ElMessage.error(`下限不能小于${down}`);
} else if (+from > +up) { } else if (+from > +up) {
...@@ -242,7 +260,7 @@ const changeWarningThresholdFrom = (index) => { ...@@ -242,7 +260,7 @@ const changeWarningThresholdFrom = (index) => {
if (rows.length == 0) return; if (rows.length == 0) return;
try { try {
rows.forEach((e) => { rows.forEach((e) => {
if (+e.up >= +from > +e.down) { if (e.up !== "" && e.down !== "" && +e.up >= +from > +e.down) {
throw ""; throw "";
} }
}); });
...@@ -252,13 +270,13 @@ const changeWarningThresholdFrom = (index) => { ...@@ -252,13 +270,13 @@ const changeWarningThresholdFrom = (index) => {
} }
}; };
const inputNum = (index, key) => { const inputNum = (index, key) => {
state.form.ruleRows[index][key] = state.form.ruleRows[index][key].replace(/[^\d]/g, ""); 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 != "" && +from > +to)) { if ((index == 0 && +to > +up) || (down != "" && +to < +down) || (from != "" && +from > +to)) {
if (+to > +up) { if (+to > +up) {
ElMessage.error(`上限不能超过${up}`); ElMessage.error(`上限不能超过${up}`);
} else if (+to < +down) { } else if (+to < +down) {
...@@ -273,7 +291,7 @@ const changeWarningThresholdTo = (index) => { ...@@ -273,7 +291,7 @@ const changeWarningThresholdTo = (index) => {
if (rows.length == 0) return; if (rows.length == 0) return;
try { try {
rows.forEach((e) => { rows.forEach((e) => {
if (+e.up > +to > +e.down) { if (e.up !== "" && e.down !== "" && +e.up > +to > +e.down) {
throw ""; throw "";
} }
}); });
...@@ -287,13 +305,15 @@ const removeRule = (index) => { ...@@ -287,13 +305,15 @@ const removeRule = (index) => {
}; };
watch( watch(
() => props.form, () => props.form,
(f) => { (n) => {
if (!f?.ruleRows) { if (!n || n?.length == 0) {
getRuleTypeOptions();
createRule(); createRule();
return; return;
} }
getRuleTypeOptions(() => {
state.form.ruleRows = state.form.ruleRows =
f.ruleRows.map((e) => { n?.map((e) => {
return { return {
from: e.from, from: e.from,
to: e.to, to: e.to,
...@@ -303,6 +323,7 @@ watch( ...@@ -303,6 +323,7 @@ watch(
if (state.form.ruleRows.length == 0) { if (state.form.ruleRows.length == 0) {
createRule(); createRule();
} }
});
}, },
{ {
deep: true, deep: true,
...@@ -325,7 +346,7 @@ defineExpose({ ...@@ -325,7 +346,7 @@ defineExpose({
&-item { &-item {
max-width: 1080px; max-width: 1080px;
width: 100%; width: 100%;
padding-left: 110px; padding-left: 120px;
:deep(.el-table thead th) { :deep(.el-table thead th) {
background-color: #f5f6f9; background-color: #f5f6f9;
} }
......
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
// max(container_fs_usage_bytes{pod!=\"\", namespace!=\"arms-prom\",namespace!=\"monitoring\"}) by (pod_name, namespace, device)/max(container_fs_limit_bytes{pod!=\"\"}) by (pod_name,namespace, device) * 100
const setParams = (res, { id }) => {
console.log('res: ', res);
let isEmpty = res.type_com_ref.isEmpty
let params = {
// 预警规则名称
metric_name: res.name,
// 持续时间
duration: +res.time,
// 持续时间单位
duration_unit: res.unit,
// 检查周期
check_period: +res.inspection_cycle,
// 预警通知方式
notify_method: res.manual_distribution_form.method,
// 预警通知人员列表
notify_recipients: res.manual_distribution_form.lists.map(e => {
return {
system_account: `${e.user_id}`,
user_name: `${e.user_name}`,
phone: `${e.phone}`
}
}),
// 消息推送次数
notify_push_count: +res.push_num,
// 消息推送频率
notify_push_frequency: +res.push_frequency,
// 是否立即启用
is_enabled: res.enabled ? 1 : 2
}
let params_push = {
// 自定义传参
custom: () => {
return {
detection_type: 2,
// 预警分类
class_parent_name: res.type_com_ref.warn_target,
// 预警对象
class_name: res.type_com_ref.warn_type,
// 预警指标
metric_config_name: res.type_com_ref.warn_indicator,
// 指标表达式
expr: res.type_com_ref.indicator_expression || "",
// 预警规则(下拉)
alert_rule_type: res.type_com_ref.rule_type,
// 预警规则对象数组
alert_condition,
alert_range: []
}
},
// 静态阈值传参
static: () => {
return {
detection_type: 1,
// 预警对象
class_id: +res.type_com_ref.warn_type,
metric_config_id: res.type_com_ref.warn_indicator,
// 报警范围(指标)
alert_range: res.type_com_ref.warning_scpoe_form.map(e => {
return {
variable_name: e.variable_name,
metric_name: e.metric_name,
chinese_name: e.chinese_name,
metric_label: e.metric_label,
is_required: e.is_required,
is_linked: e.is_linked,
value: e.select == 'all' ? '.*' : e.value,
compare: e.select == 'all' ? '=~' : e.select
}
}),
// // 预警规则(下拉)
// alert_rule_type: res.module_data.alert_rule_type,
}
}
}
let alert_condition = []
// debugger;
if (isEmpty) {
alert_condition = [{
thresholds_max: 0,
thresholds_min: 0,
risk_level: +res.type_com_ref.risk_level
}]
} else {
alert_condition = res.type_com_ref.ruleRows.map(e => {
return {
thresholds_max: +e.to,
thresholds_min: +e.from,
risk_level: +e.risk_level
}
})
}
params = {
...params,
...params_push[res.type_key](),
// 预警规则对象数组
alert_condition,
}
if (id) {
params.id = id
}
return params;
}
export const Save = (res, p, cb) => {
let params = setParams(res, p);
console.log('params: ', params);
return;
axios[p.id ? 'put' : 'post']('/v1/api/alert_rules', params).then(res => {
if (res.data.code == 200) {
ElMessage.success(`${p.id ? '编辑' : '新增'}成功`)
cb && cb()
} else {
ElMessage.error(res.data.data)
}
})
}
\ No newline at end of file
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