Commit e8660ffb authored by 张俊's avatar 张俊
parents 4f92a0d9 72566ef3
......@@ -13,7 +13,7 @@
<span class="status" :class="`status-${valueData.status}`"></span>
<span>{{ STATUS_OBJ[valueData[item.prop]] }}</span>
</span>
<span v-else :title="valueData[item.prop]">{{ valueData[item.prop] }}</span>
<span v-else :title="valueData[item.prop]">{{ valueData[item.prop] || "-" }}</span>
</span>
</div>
</div>
......
......@@ -27,7 +27,9 @@ const params = {};
const SaveSubmit = async () => {
let res = await add_form.value.Submit();
if (!res) return;
Save(res);
Save(res, { id, class_id }, () => {
Cancle();
});
};
const Cancle = () => {
router.go(-1);
......
<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>
<template #create_time="{ valueData }">
<span>{{
valueData.create_time ? valueData.create_time.split("+")[0].replace("T", " ").replace("Z", " ") : "-"
}}</span>
</template>
<template #update_time="{ valueData }">
<span>{{
valueData.update_time ? valueData.update_time.split("+")[0].replace("T", " ").replace("Z", " ") : "-"
}}</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"></Info>
</div>
</div>
</div>
</template>
<script setup></script>
<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";
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 = {
empty: "",
1: "百分比范围",
2: "毫秒范围",
3: "秒范围",
4: "个范围",
5: "温度范围",
};
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,
alert_rule_type: "1",
};
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getInfoData();
});
</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;
}
}
}
: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>
......@@ -17,7 +17,8 @@
import { onBeforeMount, ref } from "vue";
import bgBreadcrumb from "@/components/bg-breadcrumb.vue";
import addForm from "../modules/add-form.vue";
import { Save, URL } from "../modules/interface.js";
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();
......@@ -34,66 +35,42 @@ const Cancle = () => {
router.go(-1);
};
const getInfoData = () => {
// axios
// .get(URL, {
// params: {
// id: id,
// },
// })
// .then((res) => {
// if (res.data.code == 200) {
// console.log(res.data.data);
// } else {
// ElMessage.error(res.data.data);
// }
// });
let res = {
id: "20da8f87-628a-4f0c-bd9c-0ad176d18d59",
class_id: 101,
metric_name: "xx请求次数告警",
expr: 'shttp_requests_total{method="GET",$pod$}',
duration: 5,
duration_unit: "m",
check_period: 3,
is_enabled: 1,
alert_rule_type: "9f1e6170-65e8-4e14-9c17-6a7b87a900a7",
created_by: "",
created_at: "2023-06-28 17:28:29",
updated_by: "",
updated_at: "2023-06-28 17:54:33",
alert_range: [
{
variable_name: "$pod$",
metric_name: "shttp_requests_total",
metric_label: "pod",
chinese_name: "demoString",
is_required: true,
is_linked: true,
axios
.get("/v1/api/metric_config", {
params: {
id: id,
},
],
};
infoData.value = {
name: res.metric_name,
indicator_expression: res.expr,
rule_type: res.alert_rule_type,
time: res.duration,
unit: res.duration_unit,
inspection_cycle: res.check_period,
warningScopeRows:
res.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,
})
.then((res) => {
if (res.data.code == 200) {
console.log(res.data.data);
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,
};
}) || [],
state: res.is_enabled,
res: res,
};
} else {
ElMessage.error(res.data.data);
}
});
};
onBeforeMount(() => {
getInfoData();
......
......@@ -4,7 +4,7 @@
<div class="detail_container-main">
<Slide v-model="node" />
<div class="main-content">
<bg-filter-group @search="changeSearch" v-model="filter.search" placeholder="请输入指标名称">
<bg-filter-group @search="changeSearch" v-model="filter.metric_name" placeholder="请输入指标名称">
<template v-slot:left_action>
<div class="apaas_button">
<el-button type="primary" @click="addRule">
......@@ -22,10 +22,10 @@
<div class="left-filter filter_list">
<div class="filter_item">
<span class="filter_title">启用状态</span>
<el-select v-model="filter.state" placeholder="请选择" style="width: 300px">
<el-select v-model="filter.is_enabled" placeholder="请选择" style="width: 300px">
<el-option
v-for="(item, index) in stateOptions"
:key="'stateOptions' + index"
v-for="(item, index) in isEnabledOptions"
:key="'isEnabledOptions' + index"
:label="item.name"
:value="item.value">
</el-option>
......@@ -60,25 +60,25 @@
:isIndex="true"
:select="true"
:stripe="true">
<template v-slot:indicator_name="{ row }">
<template v-slot:metric_name="{ row }">
<span class="can_click_text" @click="goDetail(row)">
{{ row.indicator_name }}
{{ row.metric_name }}
</span>
</template>
<template #state="{ row }">
<template #is_enabled="{ row }">
<bg-switch
@click="stateChange(row)"
:labels="['否', '是']"
:values="[0, 1]"
v-model="row.state"></bg-switch>
:values="[2, 1]"
v-model="row.is_enabled"></bg-switch>
</template>
<template v-slot:created_time="{ row }">
{{ row.created_time ? row.created_time.split("+")[0].replace("T", " ").replace("Z", " ") : "-" }}
<template v-slot:created_at="{ row }">
{{ row.created_at ? row.created_at.split("+")[0].replace("T", " ").replace("Z", " ") : "-" }}
</template>
<template v-slot:action="{ row }">
<bg-table-btns2 :limit="3" :tableData="tableRows">
<bg-table-btn :disabled="row.state != 0" @click="editRow(row)">编辑</bg-table-btn>
<bg-table-btn :disabled="row.state != 0" @click="deleteRow(row)">删除</bg-table-btn>
<bg-table-btn :disabled="row.is_enabled != 2" @click="editRow(row)">编辑</bg-table-btn>
<bg-table-btn :disabled="row.is_enabled != 2" @click="deleteRow(row)">删除</bg-table-btn>
</bg-table-btns2>
</template>
</bg-table>
......@@ -95,7 +95,7 @@
</div>
<!-- 删除 -->
<el-dialog class="dialog_box" title="删除" v-model="delDialog" width="420px">
<div style="padding: 20px 0">确定要删除吗?</div>
<div>确定要删除吗?</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="delDialog = false">取消</el-button>
......@@ -118,13 +118,15 @@ const node = ref({});
watch(
() => node.value,
(n) => {
console.log(n);
if (n?.data.class_id) {
getTableRows();
}
},
{ deep: true }
);
const dataTable = ref(null);
const state = reactive({
stateOptions: [
isEnabledOptions: [
{
name: "全部",
value: "",
......@@ -134,27 +136,27 @@ const state = reactive({
value: 1,
},
{
name: "",
name: "",
value: 2,
},
], // 状态
headers: [
{
label: "指标名称",
prop: "indicator_name",
prop: "metric_name",
width: 200,
},
{
label: "是否启用",
prop: "state",
prop: "is_enabled",
},
{
label: "创建人",
prop: "created_user",
prop: "created_by",
},
{
label: "创建时间",
prop: "created_time",
prop: "created_at",
width: 160,
},
{
......@@ -166,11 +168,11 @@ const state = reactive({
],
filter: {
notice_method: "", // 通知方式
state: "", // 状态
is_enabled: "", // 状态
time: [],
search: "",
metric_name: "",
page: 1,
limit: 10,
page_size: 10,
},
tableRows: [], // 表格数据
selected: [], //选择数据
......@@ -184,11 +186,11 @@ const changePage = (page) => {
getTableRows();
}; // 改变页码
const changeSize = (size) => {
state.filter.limit = size;
state.filter.page_size = size;
changePage(1);
}; // 改变每页条数
const changeSearch = (val) => {
state.filter.search = val;
state.filter.metric_name = val;
changePage(1);
};
const filterAction = () => {
......@@ -196,50 +198,40 @@ const filterAction = () => {
};
const filterClear = () => {
state.filter = {
state: "", // 状态
is_enabled: "", // 状态
time: [],
search: "",
metric_name: "",
page: 1,
limit: 10,
page_size: 10,
};
changePage(1);
};
const selectable = (row, index) => {
return row.state === 0;
return row.is_enabled === 2;
};
const getTableRows = () => {
let params = { ...state.filter };
state.tableTotal = 23;
state.tableRows = [
{
id: 1,
indicator_name: "磁盘使用率",
state: 1,
created_user: "李四",
created_time: "2020-01-01 00:00:00",
},
{
id: 2,
indicator_name: "磁盘使用率",
state: 0,
created_user: "李四",
created_time: "2020-01-01 00:00:00",
},
{
id: 3,
indicator_name: "磁盘使用率",
state: 1,
created_user: "李四",
created_time: "2020-01-01 00:00:00",
},
];
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").then((res) => {
if (res.data.code == 200) {
state.tableRows =
res.data.data?.list?.map((e) => {
return {
...e,
};
}) || [];
state.tableTotal = res.data.data.total_count;
}
});
};
const goDetail = (row) => {
router.push({
path: "/forewarning/rule-set/detail",
path: "/forewarning/indicator-config/detail",
query: {
id: row.id,
class_id: node.value.data.id,
class_id: node.value.data.class_id,
type_name: node.value.node.parent.data.class_name,
target_name: node.value.data.class_name,
},
});
}; // 查看详情
......@@ -250,10 +242,10 @@ const deleteRow = (row) => {
state.actionRow = row;
state.delType = 1;
state.delDialog = true;
console.log("删除");
// console.log("删除");
}; // 删除
const batchDelete = () => {
console.log("批量删除");
// console.log("批量删除");
if (!state.selected || state.selected.length == 0) {
ElMessage.error("请先勾选要删除的数据");
return;
......@@ -270,53 +262,63 @@ const delConfirm = () => {
return e.id;
});
}
console.log(ids);
// console.log(ids);
state.delDialog = false;
setTimeout(() => {
clearSelected();
changePage(1);
}, 200);
axios
.delete("/v1/api/metric_config", {
data: {
ids,
},
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success("删除成功");
changePage(1);
clearSelected();
} else {
ElMessage.error(res.data.msg);
}
});
}; // 确定删除
const clearSelected = () => {
dataTable.value.clearTable();
}; // 清空
const addRule = () => {
console.log("新增");
// console.log("新增");
router.push({
path: `/forewarning/indicator-config/add`,
query: {
class_id: node.value.data.id,
class_id: node.value.data.class_id,
},
});
}; // 新增规则
const editRow = (row) => {
console.log("编辑");
// console.log("编辑");
router.push({
path: `/forewarning/indicator-config/edit`,
query: {
id: row.id,
class_id: node.value.data.id,
class_id: node.value.data.class_id,
},
});
}; // 编辑
const stateChange = (row) => {
console.log("更改状态");
// axios
// .put(`/xxx/xxx?id=${row.id}&state=${row.state}`)
// .then((res) => {
// if (res.data.code == 200) {
// ElMessage.success(res.data.msg);
// changePage(1);
// } else {
// ElMessage.error(res.data.data);
// row.state = row.state == 0 ? 1 : 0;
// }
// });
const stateChange = async (row) => {
await nextTick();
const params = {
id: row.id,
is_enabled: row.is_enabled,
};
axios.put("/v1/api/metric_config", params).then((res) => {
if (res.data.code == 200) {
ElMessage.success(`状态更新成功`);
getTableRows();
} else {
row.is_enabled = row.is_enabled == 1 ? 2 : 1;
ElMessage.error(res.data.msg);
}
});
};
onBeforeMount(() => {
getTableRows();
});
const { headers, tableRows, tableTotal, filter, noticeTypes, stateOptions, delDialog } = toRefs(state);
const { headers, tableRows, tableTotal, filter, noticeTypes, isEnabledOptions, delDialog } = toRefs(state);
</script>
<style lang="scss" scoped>
......
......@@ -150,7 +150,7 @@ const props = defineProps({
const tableSelOptions = ["", ""];
const ruleTypeOptions = {
empty: "",
1: "百分比范围",
"9f1e6170-65e8-4e14-9c17-6a7b87a900a7": "百分比范围",
2: "毫秒范围",
3: "秒范围",
4: "个范围",
......@@ -329,7 +329,7 @@ watch(
async (n) => {
if (!n) return;
state.form.warningScopeRows =
n.warningScopeRows.map((e) => {
n.warningScopeRows?.map((e) => {
return {
key: e.key,
input_indicator_tag: e.input_indicator_tag,
......
import { ElMessage } from "element-plus";
import axios from "@/request/http.js";
const setParams = (res, { id, class_id }) => {
let params = {
class_id,
......@@ -25,15 +26,14 @@ const setParams = (res, { id, class_id }) => {
}
return params;
}
export const URL = "https://so.wodcloud.co/v1/api/metric_config"
export const Save = (res, p) => {
export const Save = (res, p, cb) => {
let params = setParams(res, p);
console.log("params: ", params);
// axios[id ? 'put' : 'post'](URL, params).then(res => {
// if(res.data.code == 200){
// console.log('success');
// }else{
// ElMessage.error(res.data.data)
// }
// })
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)
}
})
}
\ No newline at end of file
......@@ -17,8 +17,9 @@
default-expand-all
:data="slideTree"
:current-node-key="selectId"
node-key="id"
node-key="class_id"
empty-text="暂无数据"
:props="treeProps"
:highlight-current="true"
:expand-on-click-node="false"
:filter-node-method="filterNode"
......@@ -69,7 +70,8 @@
<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-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-form-item>
<el-form-item label="预警对象" prop="target">
......@@ -101,6 +103,8 @@
<script setup>
import { nextTick, onBeforeMount, reactive, ref } from "vue";
import GapTitle from "@/components/gap-title.vue";
import axios from "@/request/http.js";
import { ElMessage } from "element-plus";
const props = defineProps({
modelValue: {
type: Object,
......@@ -109,55 +113,35 @@ const props = defineProps({
});
const search = ref("");
let slideTree = ref([]);
const treeProps = {
// 组织树获取数据规则
children: "children",
label: "class_name",
};
const treeRef = ref(null);
const selectId = ref("");
const getSlideTree = async () => {
slideTree.value = [
{
id: 1,
label: "容器云",
children: [
{
id: 11,
label: "容器集群",
},
{
id: 12,
label: "容器节点",
},
{
id: 13,
label: "工作负载",
},
{
id: 4,
label: "网关",
},
],
},
{
id: 2,
label: "机房",
},
{
id: 3,
label: "机柜",
},
{
id: 4,
label: "服务器",
},
{
id: 5,
label: "数据库/达梦数据库",
},
];
await nextTick();
treeRef.value.setCurrentKey(slideTree.value[0].children[0].id);
setTimeout(() => {
const node = treeRef.value.getNode(slideTree.value[0].children[0]);
treeNodeChoose(slideTree.value[0].children[0], node);
}, 1000);
const getSlideTree = () => {
axios.get("/v1/api/alert_class/tree").then(async (res) => {
if (res.data.code == 200) {
slideTree.value = res.data.data;
try {
slideTree.value.forEach((e) => {
if (e.children && e.children.length > 0) {
throw e.children[0];
}
});
} catch (item) {
await nextTick();
treeRef.value.setCurrentKey(item.class_id);
const node = treeRef.value.getNode(item);
if (node) {
treeNodeChoose(item, node);
}
}
} else {
ElMessage.error(res.data.msg);
}
});
};
const filterNode = (value, data) => {
if (!value) return data;
......@@ -172,6 +156,7 @@ const Add = () => {
};
const emits = defineEmits(["undate:modelValue"]);
const treeNodeChoose = (data, node) => {
console.log("data, node: ", data, node);
if (node.level == 1) return;
emits("update:modelValue", { data, node });
};
......@@ -209,8 +194,8 @@ const operations = {
label: () => "上移",
disabled: (node, data) => {
let arr = getBrotherNodes(node);
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let id = data.class_id;
let i = arr.findIndex((e) => e.class_id == id);
return 0 == i;
},
},
......@@ -218,8 +203,8 @@ const operations = {
label: () => "下移",
disabled: (node, data) => {
let arr = getBrotherNodes(node);
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let id = data.class_id;
let i = arr.findIndex((e) => e.class_id == id);
return arr.length - 1 == i;
},
},
......@@ -240,38 +225,49 @@ const Operation = (key, node, data) => {
if (node.level == 1) {
addWarnType.value = true;
await nextTick();
state.form.name = data.label;
state.form.name = data.class_name;
} else {
addWarnTarget.value = true;
await nextTick();
state.form_target.type = activeTree.value.data.id;
state.form_target.target = data.label;
state.form_target.type = activeTree.value.data.class_id;
state.form_target.target = data.class_name;
}
isEditWarnType.value = true;
},
2: () => {
addWarnTarget.value = true;
isEditWarnType.value = false;
state.form_target.type = activeTree.value.data.id;
state.form_target.type = activeTree.value.data.class_id;
},
3: () => {
delWarnType.value = true;
},
4: () => {
let arr = getBrotherNodes(node);
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let prev = arr[i - 1];
move(data.class_id, "up");
},
5: () => {
let arr = getBrotherNodes(node);
let id = data.id;
let i = arr.findIndex((e) => e.id == id);
let next = arr[i + 1];
move(data.class_id, "down");
},
};
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_target_form = ref(null);
const state = reactive({
......@@ -298,8 +294,23 @@ const Cancel = async () => {
const Save = () => {
add_warn_type_form.value.validate((valid) => {
if (valid) {
console.log(state.form);
Cancel();
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();
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
} else {
return false;
}
......@@ -313,8 +324,23 @@ const CancelAddWarnTarget = async () => {
const SaveAddWarnTarget = () => {
add_warn_target_form.value.validate((valid) => {
if (valid) {
console.log(state.form_target);
Cancel();
const params = {
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 {
return false;
}
......@@ -324,8 +350,21 @@ const CancelDel = () => {
delWarnType.value = false;
};
const ConfirmDel = () => {
console.log(activeTree.value.own);
CancelDel();
axios
.delete("/v1/api/alert_class", {
data: {
class_id: activeTree.value.own.class_id,
},
})
.then((res) => {
if (res.data.code == 200) {
ElMessage.success("删除成功");
CancelDel();
getSlideTree();
} else {
ElMessage.error(res.data.msg);
}
});
};
onBeforeMount(() => {
getSlideTree();
......
......@@ -155,21 +155,26 @@
v-model="closeWarningDialog"
width="400px"
:before-close="cancelCloseWarningDialog">
<el-form ref="closeForm" :model="closeFormData" :rules="closeRules" label-width="80px" class="bg_form">
<el-form-item label="关闭备注" prop="close_notes">
<el-input
v-model="closeFormData.close_notes"
type="textarea"
:autosize="{ minRows: 2 }"
show-word-limit
maxlength="30"
resize="vertical"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item label="" prop="close_remind" style="margin-bottom: 0px">
<el-checkbox v-model="closeFormData.close_remind" label="三天内将不再推送该预警信息" />
</el-form-item>
</el-form>
<div style="padding-top: 20px">
<el-form ref="closeForm" :model="closeFormData" :rules="closeRules" label-width="80px" class="bg_form">
<el-form-item label="关闭备注" prop="close_notes">
<el-input
v-model="closeFormData.close_notes"
type="textarea"
:autosize="{ minRows: 2 }"
show-word-limit
maxlength="30"
resize="vertical"
placeholder="请输入内容"></el-input>
</el-form-item>
<el-form-item label="" class="no-el-label" prop="close_remind" style="margin-bottom: 0px">
<el-checkbox v-model="closeFormData.close_remind">
<div>三天内将不再自动推送该告警信息给处置人员,</div>
<div>可手动推送,但告警数据依然会出现</div>
</el-checkbox>
</el-form-item>
</el-form>
</div>
<template v-slot:footer>
<div class="apaas_button">
<el-button type="default" @click="cancelCloseWarningDialog">取消</el-button>
......@@ -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>
......@@ -63,11 +63,11 @@ const labelData = [
],
[
{
label: "预警对象",
label: "预警分类",
prop: "warning_target",
},
{
label: "预警分类",
label: "预警对象",
prop: "warning_type",
},
],
......
......@@ -169,11 +169,11 @@ const state = reactive({
width: 200,
},
{
label: "预警对象",
label: "预警分类",
prop: "warning_object",
},
{
label: "预警分类",
label: "预警对象",
prop: "warning_type_name",
},
{
......
......@@ -28,20 +28,39 @@
<div class="add-form-item">
<div class="duration">
<el-form-item label="持续时间" prop="time">
<span>当预警持续</span>
<el-input v-model="state.form.time" placeholder="请输入持续时间" @input="inputNum"></el-input>
</el-form-item>
<el-form-item label="" prop="time" class="no-el-label">
<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>
<span>时产生报警</span>
<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">
<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-select>
<div class="cycle-unit">分钟</div>
</el-form-item>
</div>
<gap-title :hasLine="true" title="预警工单推送"></gap-title>
......@@ -205,25 +224,37 @@ defineExpose({
}
}
.duration {
flex: 1;
display: flex;
align-items: center;
gap: 8px;
:deep(.el-form-item__content) {
display: flex;
align-items: center;
gap: 8px;
> .el-input {
:deep(.el-form-item) {
flex: 1;
.el-input {
margin-right: 8px;
flex: 1;
width: 80px;
}
}
.no-el-label {
:deep(.el-form-item__content) {
.el-select {
width: 80px;
}
.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;
// }
// }
}
:deep(.el-switch__inner) {
.is-hide {
......@@ -235,6 +266,26 @@ defineExpose({
border-top-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 {
......
......@@ -5,7 +5,7 @@
<el-form-item label="预警对象" prop="warn_target">
<el-input
v-model="state.form.warn_target"
placeholder="请输入"
placeholder="请输入预警对象"
:disabled="isEdit"
:maxlength="20"
show-word-limit
......@@ -15,7 +15,7 @@
<el-form-item label="预警分类" prop="warn_type">
<el-input
v-model="state.form.warn_type"
placeholder="请输入"
placeholder="请输入预警分类"
:disabled="isEdit"
clearable
:maxlength="20"
......@@ -25,7 +25,7 @@
<el-form-item label="预警指标" prop="warn_indicator">
<el-input
v-model="state.form.warn_indicator"
placeholder="请输入"
placeholder="请输入预警指标"
:disabled="isEdit"
:maxlength="30"
show-word-limit
......@@ -97,7 +97,7 @@
<el-select
style="flex: 1"
v-model="state.form.ruleRows[$index].risk_level"
placeholder="请选择">
placeholder="请选择风险程度">
<el-option
v-for="item in riskLevelOptions($index)"
:key="item.id"
......@@ -175,16 +175,15 @@ const state = reactive({
ruleRows: [],
},
rules: {
warn_target: [{ required: true, message: "请输入", trigger: "blur" }],
warn_type: [{ required: true, message: "请输入", trigger: "blur" }],
warn_target: [{ required: true, message: "请输入预警对象", trigger: "blur" }],
warn_type: [{ required: true, message: "请输入预警分类", trigger: "blur" }],
warn_indicator: [{ validator: validateWarnIndex, trigger: "blur" }],
indicator_expression: [{ required: true, message: "请输入", trigger: "blur" }],
rule_type: [{ required: true, message: "请选择", trigger: "change" }],
indicator_expression: [{ required: true, message: "请输入预警指标", trigger: "blur" }],
},
tableRules: {
from: [{ 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 = () => {};
......
......@@ -21,8 +21,11 @@
style="flex: 1"
v-model.number="state.form.ruleRows[$index].from"
placeholder="请输入"
@input="changeWarningThresholdFrom($index)">
<template v-if="state.form.rule_type != 'empty'" #append>ms</template>
@input="inputNum($index, 'from')"
@blur="changeWarningThresholdFrom($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit
}}</template>
</el-input>
</el-form-item>
<span class="to">-</span>
......@@ -32,8 +35,11 @@
v-model.number="state.form.ruleRows[$index].to"
placeholder="请输入"
clearable
@input="changeWarningThresholdTo($index)">
<template v-if="state.form.rule_type != 'empty'" #append>ms</template>
@input="inputNum($index, 'to')"
@blur="changeWarningThresholdTo($index)">
<template v-if="state.form.rule_type != 'empty'" #append>{{
ruleTypeOptions[props.rule_type].unit
}}</template>
</el-input>
</el-form-item>
</div>
......@@ -77,13 +83,62 @@
<script setup>
import { computed, reactive, ref, watch } from "vue";
import gapTitle from "@/components/gap-title.vue";
import { ElMessage } from "element-plus";
const props = defineProps({
form: {
type: Object,
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({
form: {
ruleRows: [],
......@@ -160,11 +215,26 @@ const setLimits = (index) => {
}) || []
);
};
const limit = computed(() => {
return (
ruleTypeOptions[props.rule_type].limit || {
down: "",
up: "",
}
);
});
const changeWarningThresholdFrom = (index) => {
let { down, up } = limit.value;
if (down === "") return;
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 = "";
return;
}
......@@ -177,14 +247,25 @@ const changeWarningThresholdFrom = (index) => {
}
});
} catch (e) {
ElMessage.error(`该范围已被设置`);
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) => {
let { down, up } = limit.value;
if (up === "") return;
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 = "";
return;
}
......@@ -197,6 +278,7 @@ const changeWarningThresholdTo = (index) => {
}
});
} catch (e) {
ElMessage.error(`该范围已被设置`);
state.form.ruleRows[index].to = "";
}
};
......
......@@ -52,7 +52,7 @@
<el-input
class="warn-scpoe-input-value"
v-model="state.form.warning_scpoe_form[index].value"
placeholder="请输入"
:placeholder="`请输入${item.chinese_name}`"
v-if="!showSelect.includes(item.select)"
:disabled="item.select == 1">
</el-input>
......@@ -60,7 +60,7 @@
class="warn-scpoe-input-value"
v-else
v-model="item.value"
placeholder="请选择"
:placeholder="`请选择${item.chinese_name}`"
filterable
:loading="item.loading"
remote
......@@ -83,7 +83,7 @@
</el-option>
</el-select>
</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>
......@@ -370,9 +370,9 @@ defineExpose({
width: 100%;
padding-left: 8px;
.warning-scope-main {
display: grid;
grid-template-columns: 1fr 1fr;
grid-column-gap: 16px;
// display: grid;
// grid-template-columns: 1fr 1fr;
// grid-column-gap: 16px;
:deep(.el-input-group__prepend) {
border-radius: 4px;
border-top-right-radius: 0;
......@@ -385,9 +385,13 @@ defineExpose({
.warn-scpoe-select {
width: 114px !important;
:deep(.el-input__wrapper) {
background-color: #2b4695;
border-radius: 4px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
.el-input__inner {
color: #fff;
}
}
}
.warn-scpoe-input-item {
......
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