Commit 096259f2 authored by 张俊's avatar 张俊

左侧菜单样式更改

parent dd5821ad
...@@ -8,7 +8,8 @@ ...@@ -8,7 +8,8 @@
v-if="nowParent" v-if="nowParent"
:highlightParentRule="highlightParentRule" :highlightParentRule="highlightParentRule"
width="208px" width="208px"
:list="nowParent" :title="nowParent[0].menuName"
:list="nowParent[0].children"
v-show="navShow" v-show="navShow"
class="con-nav" /> class="con-nav" />
<div class="bg-main view"> <div class="bg-main view">
......
...@@ -94,3 +94,16 @@ const isCurrent = (path) => { ...@@ -94,3 +94,16 @@ const isCurrent = (path) => {
return (props.highlightParentRule && props.highlightParentRule(path)) || false; return (props.highlightParentRule && props.highlightParentRule(path)) || false;
}; };
</script> </script>
<style lang="scss" scoped>
.nav-item {
color: #202531;
margin: 10px 10px 10px 10px;
padding: 6px 10px;
border-radius: 6px;
}
.nav-item:hover {
background-color: #ebeff9;
color: #3759be;
}
</style>
<template> <template>
<div class="bg-nav" :style="{ width: width }"> <div class="bg-nav" :style="{ width: width }">
<div class="bg-nav-title" v-if="title"> <div class="bg-nav-title" v-if="title">
<h3 class="text-clip">{{ title }}</h3> <p class="text-clip"><bg-icon class="menu-icon" icon="#bg-ic-menu"></bg-icon>{{ title }}</p>
</div> </div>
<div class="bg-nav-list bg-scroll"> <div class="bg-nav-list bg-scroll">
<NavList :list="list" :highlight-parent-rule="highlightParentRule" /> <NavList :list="list" :highlight-parent-rule="highlightParentRule" />
...@@ -30,3 +30,52 @@ const props = defineProps({ ...@@ -30,3 +30,52 @@ const props = defineProps({
}, },
}); });
</script> </script>
<style lang="scss" scoped>
.bg-nav {
background-color: #fff;
box-shadow: 4px 0 4px #00076526;
transition: all 0.3s;
height: 100%;
display: flex;
flex-direction: column;
color: #202531;
.bg-nav-title {
padding: 0 0 12px 12px;
font-weight: 600;
line-height: 28px;
.menu-icon {
margin: 0 8px;
}
& > p {
font-size: 16px;
color: #3759be;
}
}
}
</style>
<style lang="scss">
// .bg-nav > .bg-nav-list ul.nav-list > li > .nav-item {
// color: #202531;
// margin: 10px 10px 10px 10px;
// padding: 6px 10px;
// border-radius: 6px;
// }
.bg-nav > .bg-nav-list ul.nav-list > li > .nav-item.current {
background-color: #ebeff9;
color: #3759be;
&::before {
display: none;
}
&::after {
display: none;
}
}
.bg-nav > .bg-nav-list ul.nav-list > li > ul.nav-list {
background-color: #fff;
}
</style>
...@@ -469,40 +469,11 @@ a { ...@@ -469,40 +469,11 @@ a {
> .nav-item { > .nav-item {
position: relative; position: relative;
display: block; display: block;
padding: 10px 10px 10px 24px;
z-index: 9; z-index: 9;
font-size: 14px; font-size: 14px;
line-height: 28px; line-height: 28px;
text-decoration: none; text-decoration: none;
color: #fff;
cursor: pointer; cursor: pointer;
&:hover:not(.nav-more),
&.current {
color: #fff;
&::before {
content: "";
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #2a4aa7;
z-index: -1;
}
&::after {
content: "";
width: 3px;
height: 100%;
position: absolute;
top: 0;
left: 0;
background-color: #5a7adc;
z-index: -1;
}
}
}
> ul.nav-list {
background-color: #202531;
} }
} }
} }
......
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="add-form-main bg-scroll">
<add-form ref="add_form"></add-form>
</div>
<div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue";
import { Save } from "../modules/interface.js";
import { useRouter, useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();
const { id, class_id } = route.query;
const add_form = ref(null);
const params = {};
const SaveSubmit = async () => {
let res = await add_form.value.Submit();
if (!res) return;
Save(res, { id, class_id }, () => {
Cancle();
});
};
const Cancle = () => {
router.go(-1);
};
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px 16px;
min-height: 100%;
.main_container {
height: calc(100% - 46px);
padding: 0;
.add-form-main {
padding: 24px 24px 16px;
height: calc(100% - 68px);
}
.add-btns {
height: 68px;
display: flex;
align-items: center;
justify-content: flex-end;
border-top: 1px solid #ddd;
padding: 0 24px;
}
}
}
</style>
<template>
<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>
<template #create_time="{ valueData }">
<span>{{ dateStringToDate(valueData.create_time) }}</span>
</template>
<template #update_time="{ valueData }">
<span>{{ dateStringToDate(valueData.update_time) }}</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>
<!-- <bg-codemirror :disabled="true" v-model="info.indicator_expression"></bg-codemirror> -->
</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]?.label || "" }}
</span>
</template>
</Info>
</div>
<gap-title :hasLine="true" title="高级配置"> </gap-title>
<div class="info">
<Info :labelData="advanced_label" :valueData="advanced_data"></Info>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onBeforeMount } 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 bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import Info from "@/components/warn-detail/info.vue";
import { METHODS } from "@/components/manual-distribution/env.js";
import { GetRuleTypeOptions, Empty, dateStringToDate } from "@/components/env.js";
const route = useRoute();
const { id, type_name, target_name } = route.query;
const STATUS_OBJ = {
1: "启用",
2: "禁用",
};
const unitOptions = {
s: "",
m: "分钟",
h: "小时",
};
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 = ref({});
const rule_label = [
[
{
prop: "alert_rule_type",
label: "预警规则类型",
},
],
];
const rule_data = ref({});
const ruleTypeOptions = ref({});
const getRuleTypeOptions = async () => {
ruleTypeOptions.value = await GetRuleTypeOptions();
getInfoData();
};
const advanced_label = [
[
{
prop: "duration",
label: "持续时间",
},
],
[
{
prop: "check_period",
label: "检查周期",
},
],
];
const advanced_data = ref({});
const warningScopeHeaders = [
{
prop: "variable_name",
label: "变量名称",
width: 100,
},
{
prop: "metric",
label: "指标标签",
},
{
prop: "chinese_name",
label: "中文名称",
},
{
prop: "is_required",
label: "是否必填",
width: 150,
},
{
prop: "is_linked",
label: "是否联动",
width: 150,
},
];
const warningScopeRows = ref([]);
const getInfoData = () => {
axios
.get("/v1/api/metric_config", {
params: {
id: id,
},
})
.then((res) => {
if (res.data.code == 200) {
let {
metric_name,
is_enabled,
expr,
created_by,
created_at,
updated_at,
alert_range,
duration,
duration_unit,
check_period,
alert_rule_type,
} = res.data.data;
info.value = {
warning_target: type_name,
warning_type: target_name,
warning_index: metric_name,
status: is_enabled,
indicator_expression: expr,
created_by: created_by,
create_time: created_at,
update_time: updated_at,
};
warningScopeRows.value = alert_range || [];
advanced_data.value = {
duration: duration == 0 ? "直接产生预警" : duration + unitOptions[duration_unit],
check_period: check_period + "分钟",
};
rule_data.value = {
alert_rule_type: alert_rule_type,
};
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getRuleTypeOptions();
});
</script>
<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;
}
}
}
:deep(.bg-table) {
th > .cell,
td > .cell {
line-height: 20px;
}
}
}
}
.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>
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="add-form-main bg-scroll">
<add-form ref="add_form" :row="infoData"></add-form>
</div>
<div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { onBeforeMount, ref } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue";
import { Save } from "../modules/interface.js";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { useRouter, useRoute } from "vue-router";
const router = useRouter();
const route = useRoute();
const { id, class_id } = route.query;
const infoData = ref({});
const add_form = ref(null);
const SaveSubmit = async () => {
let res = await add_form.value.Submit();
if (!res) return;
Save(res, { id, class_id }, () => {
Cancle();
});
};
const Cancle = () => {
router.push(`/forewarning/indicator-config?class_id=${class_id}`);
};
const getInfoData = () => {
axios
.get("/v1/api/metric_config", {
params: {
id: id,
},
})
.then((res) => {
if (res.data.code == 200) {
let res_d = res.data.data;
infoData.value = {
name: res_d.metric_name,
indicator_expression: res_d.expr,
rule_type: res_d.alert_rule_type,
time: res_d.duration,
unit: res_d.duration_unit,
inspection_cycle: res_d.check_period,
warningScopeRows:
res_d.alert_range.map((e) => {
return {
key: e.variable_name,
input_indicator_tag: e.metric_label,
indicator_scope: e.metric_name,
indicator_tag: e.metric_label,
cname: e.chinese_name,
is_required: e.is_required ? 1 : 0,
is_linkage: e.is_linked ? 1 : 0,
};
}) || [],
state: res_d.is_enabled,
res: res_d,
};
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getInfoData();
});
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px 16px;
min-height: 100%;
.main_container {
height: calc(100% - 46px);
padding: 0;
.add-form-main {
padding: 24px;
height: calc(100% - 68px);
}
.add-btns {
height: 68px;
display: flex;
align-items: center;
justify-content: flex-end;
border-top: 1px solid #ddd;
padding: 0 24px;
}
}
}
</style>
This diff is collapsed.
<template>
<div class="add-form">
<el-form :model="state.form" ref="form_ref" :rules="state.rules" label-width="120px">
<div class="add-form-item">
<el-form-item label="指标名称" prop="name">
<el-input v-model="state.form.name" :disabled="isEdit" placeholder="请输入指标名称"></el-input>
</el-form-item>
<el-form-item label="指标表达式" prop="indicator_expression">
<div class="indicator-expression">
<bg-code-editor v-model="state.form.indicator_expression"></bg-code-editor>
<!-- <bg-codemirror v-model="state.form.indicator_expression"></bg-codemirror> -->
</div>
</el-form-item>
<el-form-item label="预警范围" prop="">
<warningScope
:indicator_expression="state.form.indicator_expression"
ref="table_form_ref"
:warningScopeRows="warningScopeRows" />
</el-form-item>
<el-form-item label="预警规则类型" prop="rule_type">
<el-select style="flex: 1" v-model="state.form.rule_type" placeholder="请选择" filterable>
<el-option v-for="(value, key) in ruleTypeOptions" :key="key" :label="value.label" :value="key">
</el-option>
</el-select>
</el-form-item>
<div class="duration">
<el-form-item label="持续时间" prop="time">
<el-input v-model="state.form.time" placeholder="请输入持续时间" @input="inputNum">
<template #prepend>
<span>当预警持续</span>
</template>
<template #append>
<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-select>
</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>
</div>
<el-form-item label="检查周期" prop="inspection_cycle">
<div style="flex: 1; display: flex; align-items: center; gap: 8px">
<el-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-select>
<span>分钟</span>
</div>
</el-form-item>
<el-form-item label="是否立即启用">
<el-switch
class="bg-switch-ele"
v-model="state.form.state"
:active-value="1"
:inactive-value="0"
inline-prompt
active-text="是"
inactive-text="否" />
</el-form-item>
</div>
</el-form>
</div>
</template>
<script setup>
import { reactive, ref, computed, watch, onMounted } from "vue";
import gapTitle from "@/components/gap-title.vue";
import ManualDistributionForm from "@/components/manual-distribution/form.vue";
import { MAX_DAY, ONLY_INPUT_NUM } from "@/components/env.js";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import warningScope from "./warning-scope.vue";
import { GetRuleTypeOptions, Empty } from "@/components/env.js";
const props = defineProps({
row: {
type: Object,
default: null,
},
});
// 当前是否是编辑
const isEdit = computed(() => !!props.row);
// 获取旧数据
const warningScopeRows = computed(() => props.row?.warningScopeRows || []);
// 持续时间单位
const unitOptions = {
s: { label: "", max: MAX_DAY * 24 * 3600 },
m: { label: "分钟", max: MAX_DAY * 24 * 60 },
h: { label: "小时", max: MAX_DAY * 24 },
};
const state = reactive({
form: {
name: "",
indicator_expression: "",
rule_type: "",
time: 10,
unit: "s",
inspection_cycle: 1,
state: 1,
},
rules: {
name: [{ required: true, message: "请输入指标名称", trigger: "blur" }],
rule_type: [{ required: true, message: "请选择预警规则类型", trigger: "change" }],
indicator_expression: [{ required: true, message: "请输入指标表达式", trigger: "blur" }],
time: [{ required: true, message: "请输入持续时间", trigger: "blur" }],
},
});
// 预警规则类型下拉
const ruleTypeOptions = ref({});
const getRuleTypeOptions = async () => {
ruleTypeOptions.value = await GetRuleTypeOptions();
};
// 当预警持续输入限制
const inputNum = () => {
state.form.time = state.form.time.replace(/[^\d]/g, "");
let time = +state.form.time;
let { max } = unitOptions[state.form.unit];
if (time > +max) {
state.form.time = max;
ElMessage.closeAll();
ElMessage.error(`最大值:${max}`);
}
};
// 检查周期下拉数据
const inspectionCycleOptions = ref([1, 3, 5, 10, 20]);
// form表单元素
const form_ref = ref(null);
// table的form表单元素
const table_form_ref = ref(null);
// 提交调用
const Submit = async () => {
let form_valid = await new Promise((resolve, reject) => {
form_ref.value.validate((res) => resolve(res));
});
let table_form_valid = await table_form_ref.value.Submit();
if (form_valid && table_form_valid) {
let obj = {
...state.form,
...table_form_ref.value?.form,
};
if (!isEdit.value) {
setTimeout(() => {
state.form.indicator_expression = "";
table_form_ref.value.form_ref.resetFields();
form_ref.value.resetFields();
}, 100);
}
return obj;
}
return;
};
watch(
() => state.form.indicator_expression,
(n) => {
form_ref.value?.validateField(["indicator_expression"]);
}
);
// 监听是否是编辑,是则插入原数据
watch(
() => props.row,
async (n) => {
if (!n) return;
state.form.name = n.name;
state.form.rule_type = n.rule_type;
state.form.inspection_cycle = n.inspection_cycle || 1;
state.form.state = n.state || 1;
state.form.time = n.time || 10;
state.form.unit = n.unit || "s";
state.form.indicator_expression = n.indicator_expression;
},
{ deep: true, immediate: true }
);
// 获取第一级指标范围列表
onMounted(() => {
getRuleTypeOptions();
});
defineExpose({
Submit,
});
</script>
<style lang="scss" scoped>
.add-form {
:deep(.gap-title) {
margin-bottom: 16px;
}
&-item {
max-width: 1080px;
width: 100%;
.indicator-expression {
height: 300px;
width: 100%;
:deep(.vue-ace-editor) {
margin-top: 0;
}
}
.duration {
flex: 1;
display: flex;
align-items: center;
:deep(.el-form-item) {
flex: 1;
.el-input {
margin-right: 8px;
flex: 1;
}
.el-input-group__prepend {
width: 102px;
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.el-input-group__append {
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;
// }
// }
}
.duration-append {
display: flex;
align-items: center;
color: #404a62;
}
:deep(.el-switch__inner) {
.is-hide {
display: none;
}
}
:deep(.el-input-group__append, .el-input-group__prepend) {
border-radius: 4px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
</style>
<style lang="scss">
.el-form-item {
min-height: 36px;
label {
height: 36px;
line-height: 36px;
}
.el-input__inner {
min-height: 34px;
}
}
</style>
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
const setParams = (res, { id, class_id }) => {
let params = {
class_id: +class_id,
metric_name: res.name,
expr: res.indicator_expression,
alert_range:
res.warningScopeRows.map((e) => {
return {
variable_name: e.key,
metric_name: e.indicator_scope,
metric_label: e.indicator_tag,
chinese_name: e.cname,
is_required: e.is_required == 1,
is_linked: e.is_linkage == 1,
};
}) || [],
duration: +res.time,
duration_unit: res.unit,
check_period: res.inspection_cycle,
is_enabled: res.state,
alert_rule_type: res.rule_type,
};
if (id) {
params.id = id;
}
return params;
};
export const Save = (res, p, cb) => {
let params = setParams(res, p);
axios[p.id ? "put" : "post"]("/v1/api/metric_config", params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(`${p.id ? "编辑" : "新增"}成功`);
cb && cb();
} else {
ElMessage.error(res.data.data);
}
});
};
<template>
<div class="my-warn-detail">
<div class="breadcrumb">
<bg-breadcrumb />
</div>
<div class="content bg-scroll">
<warn-detail :label-data="labelData" :value-data="info" :tabLabels="tabLabels" :tabDatas="tabDatas">
<template #status="{ item, valueData }">
<span class="status-body">
<span class="status" :class="`status-${valueData.status}`"></span>
<span>{{ statusOptions[valueData[item.prop]] }}</span>
</span>
</template>
</warn-detail>
</div>
</div>
</template>
<script setup>
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import warnDetail from "@/components/warn-detail/index.vue";
import { useRoute } from "vue-router";
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
import { ref, onBeforeMount } from "vue";
import { dateStringToDate } from "@/components/env";
const route = useRoute();
const { id } = route.query;
const ruleTypeOptions = ref({});
const statusOptions = {
1: "已恢复",
2: "未恢复",
3: "已关闭",
};
const riskLevels = {
1: "低风险",
2: "一般风险",
3: "较大风险",
4: "重大风险",
};
const labelData = [
[
{
label: "预警点",
prop: "warning_point",
},
{
label: "预警分类",
prop: "warning_type",
},
],
[
{
label: "预警指标",
prop: "warning_index",
},
{
label: "风险等级",
prop: "risk_level",
},
],
[
{
label: "状态",
prop: "status",
},
{
label: "预警阈值",
prop: "warning_threshold",
},
],
[
{
label: "当前报警值",
prop: "current_alarm_value",
},
{
label: "预警时间",
prop: "warning_time",
},
],
];
const info = ref({});
const tabLabels = [
{
label: "推送记录",
prop: "push",
},
{
label: "处置记录",
prop: "dispose",
},
];
const tabDatas = ref({});
const pushType = {
1: "自动推送",
2: "手动推送",
};
const getInfo = () => {
const params = {
id,
};
axios.get("/v1/api/alert", { params }).then((res) => {
if (res.data.code == 200) {
const { data } = res.data;
info.value = {
warning_point: data.alert_point,
warning_type: data.class_parent_name,
warning_index: data.class_name,
risk_level: riskLevels[data.risk_level],
status: data.status,
warning_threshold: `${data.alert_condition.thresholds_min}${
ruleTypeOptions.value[data.alert_rule_type]?.unit || ""
}-${data.alert_condition.thresholds_max}${ruleTypeOptions.value[data.alert_rule_type]?.unit || ""}`,
current_alarm_value: data.current_value + (ruleTypeOptions.value[data.alert_rule_type]?.unit || ""),
warning_time: dateStringToDate(data.alert_time),
};
tabDatas.value = {
push:
data.push_records?.map((e) => {
return {
method: e.notify_method,
person: e.system_account,
push_time: dateStringToDate(e.push_time),
push_type: pushType[e.push_type],
status: e.status,
};
}) || [],
dispose:
data.disposed_list?.map((e) => {
return {
status: e.is_disposed,
feedback: e.disposal_content,
feedback_time: dateStringToDate(e.disposal_time),
feedback_person: e.disposal_user,
};
}) || [],
};
}
});
};
const GetRuleTypeOptions = () => {
const params = {
page: 1,
page_size: 10000000000000,
class: 3,
};
axios.get(`/v1/api/dict`, { params }).then((res) => {
if (res.data.code == 200) {
res.data.data?.forEach((e) => {
let isEmptyOption = e.name == "空";
ruleTypeOptions.value[e.id] = {
label: e.name,
unit: isEmptyOption ? "" : e.unit,
};
});
getInfo();
}
});
};
onBeforeMount(() => {
GetRuleTypeOptions();
});
</script>
<style lang="scss" scoped>
.my-warn-detail {
width: 100%;
height: 100%;
padding: 0 24px 16px;
.breadcrumb {
width: 100%;
height: 46px;
}
.content {
width: 100%;
height: calc(100% - 46px);
background-color: #ffffff;
box-shadow: 0px 1px 4px 0px rgba(0, 7, 101, 0.15);
border-radius: 6px;
padding: 32px;
.status {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
$statusObj: (
1: #48ad97,
3: #9e9e9e,
2: #3759be,
);
@each $status, $color in $statusObj {
&-#{$status} {
background-color: $color;
}
}
}
.status-body {
display: flex;
align-items: center;
}
}
}
</style>
This diff is collapsed.
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="add-form-main bg-scroll">
<add-form ref="add_form"></add-form>
</div>
<div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue";
import { ElMessage } from "element-plus";
import { Save } from "../modules/interface.js";
const router = useRouter();
const Cancle = () => {
router.go(-1);
};
const add_form = ref(null);
const SaveSubmit = async () => {
let { res, cb } = await add_form.value.Submit();
if (!res) return;
Save(res, {}, () => {
Cancle();
cb && cb();
});
};
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px 16px;
min-height: 100%;
.main_container {
height: calc(100% - 46px);
padding: 0;
.add-form-main {
padding: 24px;
height: calc(100% - 68px);
}
.add-btns {
height: 68px;
display: flex;
align-items: center;
justify-content: flex-end;
border-top: 1px solid #ddd;
padding: 0 24px;
}
}
}
</style>
<template>
<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>
<div class="warn-scope" v-if="detection_type == 1 && watning_scope_data_key.length > 0">
<gap-title :hasLine="true" title="预警范围"></gap-title>
<div class="info">
<Info :labelData="warning_scope_label" :valueData="watning_scope_data"> </Info>
</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>
<!-- <bg-codemirror :disabled="true" v-model="indicator_expression"></bg-codemirror> -->
</div>
</div>
<gap-title :hasLine="true" title="预警规则"></gap-title>
<div class="info">
<bg-table border ref="ruletable" :headers="ruleHeaders" :rows="ruleRows" height="100%"> </bg-table>
</div>
<gap-title :hasLine="true" title="高级配置"> </gap-title>
<div class="info">
<Info :labelData="advanced_label" :valueData="advanced_data"> </Info>
</div>
<gap-title :hasLine="true" title="预警工单推送"> </gap-title>
<div class="info">
<Info :labelData="ticket_push_label" :valueData="ticket_push_data">
<template #notification_method="{ valueData }">
<span>{{ valueData.notification_method?.map((e) => METHODS[e]).join("") || "" }}</span>
</template>
</Info>
<div class="push-lists">
<bg-table border ref="pushtable" :headers="pushHeaders" :rows="pushRows" height="100%" :isIndex="true">
</bg-table>
</div>
</div>
</div>
</div>
</template>
<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 bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import Info from "@/components/warn-detail/info.vue";
import { METHODS } from "@/components/manual-distribution/env.js";
import { GetRuleTypeOptions, Empty, WIELESS_SMALL, WIELESS_BIG } from "@/components/env.js";
const route = useRoute();
const { id } = route.query;
const STATUS_OBJ = ["禁用", "启用"];
const ruleTypeOptions = ref({});
const selectRule = {
"=": "等于",
"!=": "不等于",
"=~": "正则匹配",
"!~": "正则不匹配",
};
const riskLevelOptions = {
4: "重大风险",
3: "较大风险",
2: "一般风险",
1: "低风险",
};
const unitOptions = {
s: "",
m: "分钟",
h: "小时",
};
const labelData = [
[
{
label: "预警规则名称",
prop: "warning_rule_name",
},
{
label: "启用状态",
prop: "status",
},
],
[
{
label: "预警分类",
prop: "warning_target",
},
{
label: "预警对象",
prop: "warning_type",
},
],
[
{
label: "预警指标",
prop: "warning_index",
},
{
label: "创建人",
prop: "create_by",
},
],
[
{
label: "创建时间",
prop: "create_time",
},
{
label: "更新时间",
prop: "update_time",
},
],
];
const info = ref({});
const warning_scope_label = ref([]);
const watning_scope_data = ref({});
const watning_scope_data_key = computed(() => {
return Object.keys(watning_scope_data.value);
});
const advanced_label = [
[
{
prop: "duration",
label: "持续时间",
},
],
[
{
prop: "inspection_cycle",
label: "检查周期",
},
],
];
const advanced_data = ref({});
const ticket_push_label = [
[
{
prop: "notification_method",
label: "预警通知方式",
},
],
[
{
prop: "push_num",
label: "消息推送次数",
},
],
[
{
prop: "push_frequency",
label: "消息推送频率",
},
],
];
const ticket_push_data = ref({});
const ruleHeaders = ref([
{
prop: "risk_level",
label: "风险程度",
},
]);
const ruleRows = ref([]);
const pushHeaders = [
{
prop: "system_account",
label: "账号",
},
{
prop: "user_name",
label: "姓名",
},
{
prop: "phone",
label: "联系方式",
},
];
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.chinese_name || e.name,
label: e.chinese_name || e.name,
},
]);
watning_scope_data.value[e.chinese_name || e.name] =
e.value == ".*" ? "全部" : `${selectRule[e.compare]} ${e.value}`;
});
let isEmpty = Empty(data.alert_rule_type, ruleTypeOptions.value);
if (!isEmpty) {
ruleHeaders.value = [
{
prop: "warning_threshold",
label: "预警阈值",
},
...ruleHeaders.value,
];
}
let unit = ruleTypeOptions.value[data.alert_rule_type]?.unit || "";
ruleRows.value = data.alert_condition.map((e) => {
let min = e.thresholds_min + unit;
if (e.thresholds_min === undefined) {
if (
data.alert_rule_type &&
ruleTypeOptions.value[data.alert_rule_type] &&
ruleTypeOptions.value[data.alert_rule_type]?.down !== ""
) {
min = ruleTypeOptions.value[data.alert_rule_type].down + unit;
} else {
min = WIELESS_SMALL;
}
}
let max = e.thresholds_max + unit;
if (e.thresholds_max === undefined) {
if (
data.alert_rule_type &&
ruleTypeOptions.value[data.alert_rule_type] &&
ruleTypeOptions.value[data.alert_rule_type].up !== ""
) {
max = ruleTypeOptions.value[data.alert_rule_type].up + unit;
} else {
max = WIELESS_BIG;
}
}
return {
warning_threshold: `${min} - ${max}`,
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 = async () => {
ruleTypeOptions.value = await GetRuleTypeOptions();
getInfoData();
};
onBeforeMount(() => {
getRuleTypeOptions();
});
</script>
<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;
}
.warn-scope {
margin-bottom: 24px;
.indicator-expression {
height: 300px;
width: 100%;
:deep(.vue-ace-editor) {
margin-top: 0;
}
}
}
.info {
max-width: 1072px;
width: 100%;
padding: 0 8px 0;
&:not(:last-child) {
padding-bottom: 24px;
}
.push-lists {
margin-top: 16px;
}
}
}
}
.status {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
margin-right: 8px;
$statusObj: (
1: #48ad97,
0: #9e9e9e,
);
@each $status, $color in $statusObj {
&-#{$status} {
background-color: $color;
}
}
}
.status-body {
display: flex;
align-items: center;
}
</style>
<template>
<div class="detail_container">
<bg-breadcrumb></bg-breadcrumb>
<div class="main_container">
<div class="add-form-main bg-scroll">
<add-form ref="add_form" :row="infoData"></add-form>
</div>
<div class="add-btns">
<el-button size="default" @click="Cancle">取消</el-button>
<el-button type="primary" size="default" @click="SaveSubmit">保存</el-button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onBeforeMount } from "vue";
import { useRouter, useRoute } from "vue-router";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
import { Save } from "../modules/interface.js";
import { Empty, GetRuleTypeOptions } from "@/components/env.js";
const infoData = ref({});
const ruleTypeOptions = ref({});
const router = useRouter();
const route = useRoute();
const { id } = route.query;
const Cancle = () => {
router.go(-1);
};
const add_form = ref(null);
const SaveSubmit = async () => {
let { res, cb } = await add_form.value.Submit();
if (!res) return;
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;
let isEmpty = Empty(data.alert_rule_type, ruleTypeOptions.value);
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,
warning_scpoe_form:
data.alert_range?.map((e) => {
return {
...e,
value: e.value == ".*" ? "" : e.value,
select: e.value == ".*" ? "all" : e.compare,
options: [],
};
}) || [],
},
};
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;
},
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,
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 getRuleTypeOptions = async (cb) => {
ruleTypeOptions.value = await GetRuleTypeOptions();
getInfoData();
};
const getStaticTypeOptions = () => {
axios.get("/v1/api/alert_class/tree").then(async (res) => {
if (res.data.code == 200) {
staticTypeOptions.value = res.data.data;
getRuleTypeOptions();
} else {
ElMessage.error(res.data.msg);
}
});
};
onBeforeMount(() => {
getStaticTypeOptions();
});
</script>
<style lang="scss" scoped>
.detail_container {
width: 100%;
height: calc(100vh - 56px);
padding: 0 24px 16px;
min-height: 100%;
.main_container {
height: calc(100% - 46px);
padding: 0;
.add-form-main {
padding: 24px;
height: calc(100% - 68px);
}
.add-btns {
height: 68px;
display: flex;
align-items: center;
justify-content: flex-end;
border-top: 1px solid #ddd;
padding: 0 24px;
}
}
}
</style>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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