Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
so-manage-ui
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
smart-operation
so-manage-ui
Commits
096259f2
Commit
096259f2
authored
Dec 28, 2023
by
张俊
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
左侧菜单样式更改
parent
dd5821ad
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
65 additions
and
6274 deletions
+65
-6274
src/App.vue
src/App.vue
+2
-1
src/bg-ui/bg-nav-list.vue
src/bg-ui/bg-nav-list.vue
+13
-0
src/bg-ui/bg-nav.vue
src/bg-ui/bg-nav.vue
+50
-1
src/bg-ui/index.scss
src/bg-ui/index.scss
+0
-29
src/page/main/forewarning/indicator-config/add/index.vue
src/page/main/forewarning/indicator-config/add/index.vue
+0
-62
src/page/main/forewarning/indicator-config/detail/index.vue
src/page/main/forewarning/indicator-config/detail/index.vue
+0
-288
src/page/main/forewarning/indicator-config/edit/index.vue
src/page/main/forewarning/indicator-config/edit/index.vue
+0
-104
src/page/main/forewarning/indicator-config/index.vue
src/page/main/forewarning/indicator-config/index.vue
+0
-451
src/page/main/forewarning/indicator-config/modules/add-form.vue
...ge/main/forewarning/indicator-config/modules/add-form.vue
+0
-273
src/page/main/forewarning/indicator-config/modules/interface.js
...ge/main/forewarning/indicator-config/modules/interface.js
+0
-40
src/page/main/forewarning/indicator-config/modules/slide.vue
src/page/main/forewarning/indicator-config/modules/slide.vue
+0
-477
src/page/main/forewarning/indicator-config/modules/warning-scope.vue
...in/forewarning/indicator-config/modules/warning-scope.vue
+0
-493
src/page/main/forewarning/list/detail/index.vue
src/page/main/forewarning/list/detail/index.vue
+0
-205
src/page/main/forewarning/list/index.vue
src/page/main/forewarning/list/index.vue
+0
-588
src/page/main/forewarning/rule-set/add/index.vue
src/page/main/forewarning/rule-set/add/index.vue
+0
-61
src/page/main/forewarning/rule-set/detail/index.vue
src/page/main/forewarning/rule-set/detail/index.vue
+0
-348
src/page/main/forewarning/rule-set/edit/index.vue
src/page/main/forewarning/rule-set/edit/index.vue
+0
-188
src/page/main/forewarning/rule-set/index.vue
src/page/main/forewarning/rule-set/index.vue
+0
-427
src/page/main/forewarning/rule-set/modules/add-form.vue
src/page/main/forewarning/rule-set/modules/add-form.vue
+0
-329
src/page/main/forewarning/rule-set/modules/custom.vue
src/page/main/forewarning/rule-set/modules/custom.vue
+0
-478
src/page/main/forewarning/rule-set/modules/gateway.vue
src/page/main/forewarning/rule-set/modules/gateway.vue
+0
-382
src/page/main/forewarning/rule-set/modules/interface.js
src/page/main/forewarning/rule-set/modules/interface.js
+0
-118
src/page/main/forewarning/rule-set/modules/static.vue
src/page/main/forewarning/rule-set/modules/static.vue
+0
-401
src/page/main/ticket/my-warn-ticket/detail/index.vue
src/page/main/ticket/my-warn-ticket/detail/index.vue
+0
-206
src/page/main/ticket/my-warn-ticket/index.vue
src/page/main/ticket/my-warn-ticket/index.vue
+0
-324
No files found.
src/App.vue
View file @
096259f2
...
...
@@ -8,7 +8,8 @@
v-if=
"nowParent"
:highlightParentRule=
"highlightParentRule"
width=
"208px"
:list=
"nowParent"
:title=
"nowParent[0].menuName"
:list=
"nowParent[0].children"
v-show=
"navShow"
class=
"con-nav"
/>
<div
class=
"bg-main view"
>
...
...
src/bg-ui/bg-nav-list.vue
View file @
096259f2
...
...
@@ -94,3 +94,16 @@ const isCurrent = (path) => {
return
(
props
.
highlightParentRule
&&
props
.
highlightParentRule
(
path
))
||
false
;
};
</
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
>
src/bg-ui/bg-nav.vue
View file @
096259f2
<
template
>
<div
class=
"bg-nav"
:style=
"
{ width: width }">
<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
class=
"bg-nav-list bg-scroll"
>
<NavList
:list=
"list"
:highlight-parent-rule=
"highlightParentRule"
/>
...
...
@@ -30,3 +30,52 @@ const props = defineProps({
},
});
</
script
>
<
style
lang=
"scss"
scoped
>
.bg-nav
{
background-color
:
#fff
;
box-shadow
:
4px
0
4px
#000765
26
;
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
>
src/bg-ui/index.scss
View file @
096259f2
...
...
@@ -469,40 +469,11 @@ a {
>
.nav-item
{
position
:
relative
;
display
:
block
;
padding
:
10px
10px
10px
24px
;
z-index
:
9
;
font-size
:
14px
;
line-height
:
28px
;
text-decoration
:
none
;
color
:
#fff
;
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
;
}
}
}
...
...
src/page/main/forewarning/indicator-config/add/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/indicator-config/detail/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/indicator-config/edit/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/indicator-config/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"detail_container-main"
>
<Slide
v-model=
"nodeData"
/>
<div
class=
"main-content"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.metric_name"
placeholder=
"请输入指标名称"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
class=
"add-btn"
@
click=
"addRule"
:disabled=
"nodeData?.node?.level == 1"
:style=
"[noType ? 'cursor: not-allowed' : '']"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
<el-button
type=
"default"
@
click=
"batchDelete"
:disabled=
"nodeData?.node?.level == 1"
:style=
"[noType ? 'cursor: not-allowed' : '']"
>
批量删除
</el-button>
<span
class=
"header_info selected-count"
>
已选择
<span
style=
"color: #202531"
>
{{
state
.
selected
.
length
}}
</span>
项
</span>
<span
class=
"header_info can_click_text clear-selected"
:class=
"
{ 'is-disabled': nodeData?.node?.level == 1 }"
@click="clearSelected">
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
启用状态
</span>
<el-select
v-model=
"filter.is_enabled"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in isEnabledOptions"
:key=
"'isEnabledOptions' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
创建时间
</span>
<el-date-picker
style=
"width: 400px"
v-model=
"filter.time"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"至"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
/>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"dataTable"
:headers=
"headers"
:rows=
"tableRows"
@
selectAc=
"selectRows"
:selectable=
"selectable"
:isIndex=
"true"
:select=
"true"
:stripe=
"true"
>
<
template
v-slot:metric_name=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"goDetail(row)"
>
{{
row
.
metric_name
}}
</span>
</
template
>
<
template
#status
="{
row
}"
>
<el-switch
v-model=
"row.status"
active-text=
"是"
inactive-text=
"否"
inline-prompt
@
change=
"stateChange(row)"
>
</el-switch>
<!--
<bg-switch
@
click=
"stateChange(row)"
:labels=
"['否', '是']"
:values=
"[2, 1]"
v-model=
"row.is_enabled"
></bg-switch>
-->
</
template
>
<
template
v-slot:created_at=
"{ row }"
>
{{
dateStringToDate
(
row
.
created_at
)
}}
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:tableData=
"tableRows"
>
<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>
</div>
<bg-pagination
:page=
"filter.page"
:size=
"filter.size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
</div>
<!-- 删除 -->
<el-dialog
class=
"dialog_box"
title=
"删除"
v-model=
"delDialog"
width=
"420px"
>
<div>
确定要删除吗?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"delDialog = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"delConfirm"
>
确定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
Slide
from
"
./modules/slide.vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
{
dateStringToDate
}
from
"
@/components/env
"
;
const
router
=
useRouter
();
const
nodeData
=
ref
({});
const
noType
=
computed
(()
=>
{
return
!
nodeData
.
value
?.
data
?.
class_id
;
});
const
active_node_id
=
ref
(
""
);
watch
(
()
=>
nodeData
.
value
,
(
n
)
=>
{
if
(
n
.
node
.
level
==
1
)
return
;
if
(
n
?.
data
.
class_id
&&
active_node_id
.
value
!=
n
?.
data
.
class_id
)
{
getTableRows
();
active_node_id
.
value
=
n
.
data
.
class_id
;
}
},
{
deep
:
true
}
);
const
dataTable
=
ref
(
null
);
const
state
=
reactive
({
isEnabledOptions
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
启用
"
,
value
:
1
,
},
{
name
:
"
禁用
"
,
value
:
2
,
},
],
// 状态
headers
:
[
{
label
:
"
指标名称
"
,
prop
:
"
metric_name
"
,
width
:
200
,
},
{
label
:
"
是否启用
"
,
prop
:
"
status
"
,
},
{
label
:
"
创建人
"
,
prop
:
"
created_by
"
,
},
{
label
:
"
创建时间
"
,
prop
:
"
created_at
"
,
width
:
160
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
136
,
fixed
:
"
right
"
,
},
],
filter
:
{
notice_method
:
""
,
// 通知方式
is_enabled
:
""
,
// 状态
time
:
[],
metric_name
:
""
,
page
:
1
,
page_size
:
10
,
},
tableRows
:
[],
// 表格数据
selected
:
[],
//选择数据
tableTotal
:
0
,
// 表格数据条数
actionRow
:
null
,
// 当前操作的数据
delDialog
:
false
,
// 删除弹窗
delType
:
0
,
// 1-单条删除 2-批量删除
});
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
page_size
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
metric_name
=
val
;
changePage
(
1
);
};
const
filterAction
=
()
=>
{
changePage
(
1
);
};
const
filterClear
=
()
=>
{
state
.
filter
=
{
is_enabled
:
""
,
// 状态
time
:
[],
metric_name
:
""
,
page
:
1
,
page_size
:
10
,
};
changePage
(
1
);
};
const
selectable
=
(
row
,
index
)
=>
{
return
row
.
is_enabled
===
2
;
};
const
getTableRows
=
()
=>
{
const
[
start_time
=
""
,
end_time
=
""
]
=
state
.
filter
.
time
||
[];
let
params
=
{
...
state
.
filter
,
class_id
:
nodeData
.
value
.
data
.
class_id
,
start_time
,
end_time
};
Reflect
.
deleteProperty
(
params
,
"
time
"
);
axios
.
get
(
"
/v1/api/metric_config/list
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
tableRows
=
res
.
data
.
data
?.
list
.
map
((
e
)
=>
{
return
{
...
e
,
status
:
e
.
is_enabled
==
1
,
};
})
||
[];
state
.
tableTotal
=
res
.
data
.
data
.
total_count
;
}
});
};
const
goDetail
=
(
row
)
=>
{
router
.
push
({
path
:
"
/forewarning/indicator-config/detail
"
,
query
:
{
id
:
row
.
id
,
class_id
:
node
.
value
.
data
.
class_id
,
type_name
:
node
.
value
.
node
.
parent
.
data
.
class_name
,
target_name
:
node
.
value
.
data
.
class_name
,
},
});
};
// 查看详情
const
selectRows
=
(
data
)
=>
{
state
.
selected
=
data
.
selection
;
};
const
deleteRow
=
(
row
)
=>
{
state
.
actionRow
=
row
;
state
.
delType
=
1
;
state
.
delDialog
=
true
;
// console.log("删除");
};
// 删除
const
batchDelete
=
()
=>
{
// console.log("批量删除");
if
(
noType
.
value
)
return
;
if
(
!
state
.
selected
||
state
.
selected
.
length
==
0
)
{
ElMessage
.
error
(
"
请先勾选要删除的数据
"
);
return
;
}
state
.
delType
=
2
;
state
.
delDialog
=
true
;
};
// 批量删除
const
delConfirm
=
()
=>
{
let
ids
=
[];
if
(
state
.
delType
==
1
)
{
ids
.
push
(
state
.
actionRow
.
id
);
}
else
{
ids
=
state
.
selected
.
map
((
e
)
=>
{
return
e
.
id
;
});
}
// console.log(ids);
state
.
delDialog
=
false
;
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
=
()
=>
{
if
(
nodeData
.
value
.
node
.
level
==
1
)
return
;
dataTable
.
value
.
clearTable
();
};
// 清空
const
addRule
=
()
=>
{
// console.log("新增");
if
(
noType
.
value
)
return
;
router
.
push
({
path
:
`/forewarning/indicator-config/add`
,
query
:
{
class_id
:
nodeData
.
value
.
data
?.
class_id
,
},
});
};
// 新增规则
const
editRow
=
(
row
)
=>
{
// console.log("编辑");
router
.
push
({
path
:
`/forewarning/indicator-config/edit`
,
query
:
{
id
:
row
.
id
,
class_id
:
nodeData
.
value
.
data
.
class_id
,
},
});
};
// 编辑
const
stateChange
=
async
(
row
)
=>
{
await
nextTick
();
const
params
=
{
id
:
row
.
id
,
is_enabled
:
row
.
status
?
1
:
2
,
};
axios
.
put
(
"
/v1/api/metric_config
"
,
params
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
`状态更新成功`
);
getTableRows
();
}
else
{
row
.
status
=
!
row
.
status
;
ElMessage
.
error
(
res
.
data
.
msg
);
}
})
.
catch
((
e
)
=>
{
row
.
status
=
!
row
.
status
;
});
};
const
{
headers
,
tableRows
,
tableTotal
,
filter
,
noticeTypes
,
isEnabledOptions
,
delDialog
}
=
toRefs
(
state
);
</
script
>
<
style
lang=
"scss"
scoped
>
.detail_container
{
width
:
100%
;
height
:
calc
(
100vh
-
56px
);
padding
:
0
24px
;
min-height
:
100%
;
&
-main
{
width
:
100%
;
height
:
calc
(
100%
-
46px
);
display
:
flex
;
align-items
:
center
;
padding-bottom
:
16px
;
}
.main-content
{
height
:
100%
;
width
:
calc
(
100%
-
336px
);
background-color
:
#fff
;
box-shadow
:
0
1px
4px
0
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
display
:
flex
;
flex-direction
:
column
;
justify-content
:
flex-start
;
align-items
:
stretch
;
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.selected-count
{
color
:
#404a62
;
font-size
:
14px
;
margin
:
0
24px
0
40px
;
}
.clear-selected
{
color
:
#3759be
;
font-size
:
14px
;
cursor
:
pointer
;
&
.is-disabled
{
color
:
#c0c4cc
;
cursor
:
not
-
allowed
;
}
}
.table_container
{
flex
:
1
;
width
:
100%
;
padding
:
0
16px
;
position
:
relative
;
.table
{
position
:
absolute
;
top
:
0
;
left
:
0
;
width
:
100%
;
height
:
calc
(
100%
-
64px
);
}
.bg-pagination
{
height
:
64px
;
position
:
absolute
;
right
:
0
;
bottom
:
0
;
padding
:
16px
;
margin-top
:
0
;
}
}
}
}
.add-btn.is-disabled
{
&
,
&
:hover
{
background-image
:
none
;
background-color
:
rgb
(
149
,
163
,
202
);
border-color
:
rgb
(
149
,
163
,
202
);
}
}
</
style
>
src/page/main/forewarning/indicator-config/modules/add-form.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/indicator-config/modules/interface.js
deleted
100644 → 0
View file @
dd5821ad
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
);
}
});
};
src/page/main/forewarning/indicator-config/modules/slide.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"main-slide"
>
<div
class=
"slide-title"
>
预警对象
</div>
<div
class=
"slide-search"
>
<el-input
v-model=
"search"
placeholder=
"请输入关键字"
clearable
@
input=
"Search"
@
clear=
"Search"
>
<template
#prefix
>
<bg-icon
style=
"font-size: 12px; color: #404a62"
icon=
"#bg-ic-search"
></bg-icon>
</
template
>
</el-input>
<el-button
type=
"primary"
size=
"default"
@
click=
"Add"
>
<bg-icon
style=
"font-size: 12px; color: #fff"
icon=
"#bg-ic-add"
></bg-icon>
</el-button>
</div>
<div
class=
"slide-tree bg-scroll"
>
<el-tree
ref=
"treeRef"
default-expand-all
:data=
"slideTree"
:current-node-key=
"selectId"
node-key=
"class_id"
empty-text=
"暂无数据"
:props=
"treeProps"
:highlight-current=
"true"
:expand-on-click-node=
"false"
:filter-node-method=
"filterNode"
@
node-click=
"treeNodeChoose"
>
<
template
#default
="{
node
,
data
}"
>
<span
class=
"custom-tree-node"
>
<span>
{{
node
.
label
}}
</span>
<el-popover
popper-class=
"tree-operation"
placement=
"right-start"
:width=
"120"
trigger=
"click"
>
<template
#reference
>
<span
class=
"operation"
@
click.stop=
""
>
<bg-icon
style=
"font-size: 12px; color: #404a62"
icon=
"#bg-ic-s-more"
></bg-icon>
</span>
</
template
>
<
template
#default
>
<ul
class=
"operation-lists"
>
<li
v-for=
"(value, key) in operations"
:key=
"key"
@
click.stop=
"Operation(key, node, data)"
>
<el-button
link
:disabled=
"value.disabled(node, data)"
>
{{
value
.
label
(
node
)
}}
</el-button>
</li>
</ul>
</
template
>
</el-popover>
</span>
</template>
</el-tree>
</div>
</div>
<el-dialog
:close-on-click-modal=
"false"
v-model=
"addWarnType"
width=
"558px"
:before-close=
"Cancel"
>
<
template
#header
>
<GapTitle
:title=
"isEditWarnType ? '编辑预警分类' : '新增预警分类'"
></GapTitle>
</
template
>
<div
style=
"padding-top: 20px"
>
<el-form
:model=
"state.form"
ref=
"add_warn_type_form"
:rules=
"state.rules"
label-width=
"80px"
>
<el-form-item
label=
"预警分类"
prop=
"name"
>
<el-input
v-model=
"state.form.name"
placeholder=
"请输入预警分类"
maxlength=
"20"
show-word-limit
></el-input>
</el-form-item>
</el-form>
</div>
<
template
#footer
>
<el-button
size=
"default"
@
click=
"Cancel"
>
取消
</el-button>
<el-button
type=
"primary"
size=
"default"
@
click=
"Save"
>
保存
</el-button>
</
template
>
</el-dialog>
<el-dialog
:close-on-click-modal=
"false"
v-model=
"addWarnTarget"
width=
"558px"
:before-close=
"CancelAddWarnTarget"
>
<
template
#header
>
<GapTitle
:title=
"isEditWarnType ? '编辑预警对象' : '新增预警对象'"
></GapTitle>
</
template
>
<div
style=
"padding-top: 20px"
>
<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.class_id"
:label=
"item.class_name"
:value=
"item.class_id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"预警对象"
prop=
"target"
>
<el-input
v-model=
"state.form_target.target"
placeholder=
"请输入预警对象"
maxlength=
"20"
show-word-limit
></el-input>
</el-form-item>
</el-form>
</div>
<
template
#footer
>
<el-button
size=
"default"
@
click=
"CancelAddWarnTarget"
>
取消
</el-button>
<el-button
type=
"primary"
size=
"default"
@
click=
"SaveAddWarnTarget"
>
保存
</el-button>
</
template
>
</el-dialog>
<el-dialog
v-model=
"delWarnType"
width=
"400px"
:before-close=
"CancelDel"
>
<
template
#header
>
<GapTitle
:title=
"`删除预警$
{activeTree.node.level == 1 ? '分类' : '对象'}`">
</GapTitle>
</
template
>
<div
style=
"padding: 20px 0"
>
是否确定删除 {{ activeTree.own.label }} 这个预警{{ activeTree.node.level == 1 ? "分类" : "对象" }}
</div>
<
template
#footer
>
<el-button
size=
"default"
@
click=
"CancelDel"
>
取消
</el-button>
<el-button
type=
"primary"
size=
"default"
@
click=
"ConfirmDel"
>
确定
</el-button>
</
template
>
</el-dialog>
</template>
<
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
"
;
import
{
useRoute
}
from
"
vue-router
"
;
const
route
=
useRoute
();
const
{
class_id
}
=
route
.
query
;
const
props
=
defineProps
({
modelValue
:
{
type
:
Object
,
default
:
()
=>
({}),
},
});
const
search
=
ref
(
""
);
let
slideTree
=
ref
([]);
const
treeProps
=
{
// 组织树获取数据规则
children
:
"
children
"
,
label
:
"
class_name
"
,
};
const
treeRef
=
ref
(
null
);
const
selectId
=
ref
(
""
);
const
getSlideTree
=
()
=>
{
axios
.
get
(
"
/v1/api/alert_class/tree
"
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
slideTree
.
value
=
res
.
data
.
data
;
async
function
nodeChoose
(
item
)
{
await
nextTick
();
treeRef
.
value
.
setCurrentKey
(
item
.
class_id
);
const
node
=
treeRef
.
value
.
getNode
(
item
);
if
(
node
)
{
treeNodeChoose
(
item
,
node
);
}
}
if
(
class_id
)
{
let
item
=
null
;
slideTree
.
value
.
forEach
((
e
)
=>
{
if
(
e
.
children
&&
e
.
children
.
length
>
0
)
{
e
.
children
.
forEach
((
e
)
=>
{
if
(
e
.
class_id
==
class_id
)
{
item
=
e
;
}
});
}
});
nodeChoose
(
item
);
return
;
}
try
{
slideTree
.
value
.
forEach
((
e
)
=>
{
if
(
e
.
children
&&
e
.
children
.
length
>
0
)
{
throw
e
.
children
[
0
];
}
});
}
catch
(
item
)
{
nodeChoose
(
item
);
}
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
const
filterNode
=
(
value
,
data
)
=>
{
if
(
!
value
)
return
data
;
return
data
.
class_name
.
includes
(
value
);
};
const
Search
=
async
()
=>
{
await
nextTick
();
treeRef
.
value
.
filter
(
search
.
value
);
};
const
Add
=
()
=>
{
addWarnType
.
value
=
true
;
};
const
emits
=
defineEmits
([
"
update:modelValue
"
]);
const
treeNodeChoose
=
(
data
,
node
)
=>
{
emits
(
"
update:modelValue
"
,
{
data
,
node
});
};
const
getBrotherNodes
=
(
node
)
=>
{
let
arr
=
[];
if
(
node
.
level
==
1
)
{
arr
=
slideTree
.
value
;
}
else
{
arr
=
node
.
parent
.
data
.
children
;
}
return
arr
;
};
const
operations
=
{
1
:
{
label
:
(
node
)
=>
{
return
node
.
level
==
1
?
"
编辑预警分类
"
:
"
编辑预警对象
"
;
},
disabled
:
()
=>
{
return
false
;
},
},
2
:
{
label
:
()
=>
"
新增预警对象
"
,
disabled
:
()
=>
{
return
false
;
},
},
3
:
{
label
:
()
=>
"
删除
"
,
disabled
:
()
=>
{
return
false
;
},
},
4
:
{
label
:
()
=>
"
上移
"
,
disabled
:
(
node
,
data
)
=>
{
let
arr
=
getBrotherNodes
(
node
);
let
id
=
data
.
class_id
;
let
i
=
arr
.
findIndex
((
e
)
=>
e
.
class_id
==
id
);
return
0
==
i
;
},
},
5
:
{
label
:
()
=>
"
下移
"
,
disabled
:
(
node
,
data
)
=>
{
let
arr
=
getBrotherNodes
(
node
);
let
id
=
data
.
class_id
;
let
i
=
arr
.
findIndex
((
e
)
=>
e
.
class_id
==
id
);
return
arr
.
length
-
1
==
i
;
},
},
};
const
addWarnType
=
ref
(
false
);
const
addWarnTarget
=
ref
(
false
);
const
delWarnType
=
ref
(
false
);
const
isEditWarnType
=
ref
(
false
);
const
activeTree
=
ref
({});
const
Operation
=
(
key
,
node
,
data
)
=>
{
activeTree
.
value
=
{
node
,
own
:
data
,
data
:
node
.
level
==
1
?
data
:
node
.
parent
.
data
,
};
let
operation_handled_fn
=
{
1
:
async
()
=>
{
if
(
node
.
level
==
1
)
{
addWarnType
.
value
=
true
;
await
nextTick
();
state
.
form
.
name
=
data
.
class_name
;
}
else
{
addWarnTarget
.
value
=
true
;
await
nextTick
();
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
.
class_id
;
},
3
:
()
=>
{
delWarnType
.
value
=
true
;
},
4
:
()
=>
{
move
(
data
.
class_id
,
"
up
"
);
},
5
:
()
=>
{
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
({
form
:
{
name
:
""
,
},
form_target
:
{
type
:
""
,
target
:
""
,
},
rules
:
{
name
:
[{
required
:
true
,
message
:
"
请输入预警分类
"
,
trigger
:
"
blur
"
}],
},
target_rules
:
{
type
:
[{
required
:
true
,
message
:
"
请选择预警分类
"
,
trigger
:
"
change
"
}],
target
:
[{
required
:
true
,
message
:
"
请输入预警对象
"
,
trigger
:
"
blur
"
}],
},
});
const
Cancel
=
async
()
=>
{
add_warn_type_form
.
value
.
resetFields
();
await
nextTick
();
addWarnType
.
value
=
false
;
};
const
Save
=
()
=>
{
add_warn_type_form
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
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
;
}
});
};
const
CancelAddWarnTarget
=
async
()
=>
{
add_warn_target_form
.
value
.
resetFields
();
await
nextTick
();
addWarnTarget
.
value
=
false
;
};
const
SaveAddWarnTarget
=
()
=>
{
add_warn_target_form
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
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
(
`预警对象
${
isEditWarnType
.
value
?
"
编辑
"
:
"
新建
"
}
成功`
);
CancelAddWarnTarget
();
getSlideTree
();
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
}
else
{
return
false
;
}
});
};
const
CancelDel
=
()
=>
{
delWarnType
.
value
=
false
;
};
const
ConfirmDel
=
()
=>
{
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
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.main-slide
{
width
:
320px
;
height
:
100%
;
background-color
:
#fff
;
box-shadow
:
0
1px
4px
0
rgba
(
0
,
7
,
101
,
0
.15
);
border-radius
:
6px
;
margin-right
:
16px
;
overflow
:
hidden
;
.slide-title
{
height
:
40px
;
background-color
:
#f7f7f9
;
display
:
flex
;
align-items
:
center
;
padding-left
:
16px
;
}
.slide-search
{
padding
:
16px
;
display
:
flex
;
align-items
:
center
;
:deep
(
.el-button
)
{
margin-left
:
8px
;
}
}
.slide-tree
{
height
:
calc
(
100%
-
108px
);
:deep
(
.el-tree-node__content
)
{
height
:
36px
;
}
.custom-tree-node
{
flex
:
1
;
display
:
flex
;
align-items
:
center
;
justify-content
:
space-between
;
font-size
:
14px
;
overflow
:
hidden
;
&
:hover
{
.operation
{
visibility
:
visible
;
}
}
.operation
{
display
:
flex
;
visibility
:
hidden
;
width
:
36px
;
height
:
36px
;
align-items
:
center
;
justify-content
:
center
;
box-shadow
:
-4px
0
4px
0px
rgba
(
0
,
7
,
101
,
0
.15
);
}
}
}
}
.add-warn-type-form
{
padding-top
:
20px
;
}
</
style
>
<
style
lang=
"scss"
>
.tree-operation
{
padding
:
4px
0
!
important
;
min-width
:
0
!
important
;
.operation-lists
{
li
{
line-height
:
34px
;
cursor
:
pointer
;
transition
:
all
300ms
;
.el-button
{
width
:
100%
;
height
:
34px
;
justify-content
:
flex-start
;
padding
:
0
16px
;
}
&
:hover
{
background-color
:
#f2f3f7
;
.el-button
{
&
:not
(
.is-disabled
)
{
color
:
#3759be
;
}
}
}
}
}
}
</
style
>
src/page/main/forewarning/indicator-config/modules/warning-scope.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<el-form
:model=
"state.form.warningScopeRows"
ref=
"form_ref"
:rules=
"tableRules"
label-width=
"0"
style=
"width: 100%"
>
<el-table
:data=
"state.form.warningScopeRows"
stripe
border
empty-text=
"请输入表达式,根据表达式$...$自动生成表格"
>
<el-table-column
v-for=
"header in warningScopeHeaders"
:prop=
"header.prop"
:key=
"header.prop"
:label=
"header.label"
:width=
"header.width"
>
<template
#default
="
{ $index }">
<div
v-if=
"header.prop == 'indicator_tag'"
>
<el-form-item
:prop=
"`[$
{$index}].input_indicator_tag`" :rules="tableRules.input_indicator_tag">
<el-input
v-model=
"state.form.warningScopeRows[$index].input_indicator_tag"
placeholder=
"请选择指标标签"
ref=
"inputRef"
@
blur=
"blurInput($index)"
@
focus=
"inputLabel($index, false)"
@
input=
"inputLabel($index, true)"
></el-input>
</el-form-item>
</div>
<div
v-else-if=
"header.prop == 'cname'"
>
<el-form-item
:prop=
"`[$
{$index}].cname`" :rules="tableRules.cname">
<el-input
style=
"flex: 1"
v-model=
"state.form.warningScopeRows[$index].cname"
:maxlength=
"20"
show-word-limit
placeholder=
"请输入中文名称"
>
</el-input>
</el-form-item>
</div>
<div
v-else-if=
"header.prop == 'is_required'"
>
<el-form-item
:prop=
"`[$
{$index}].is_required`" :rules="tableRules.is_required">
<el-select
v-model=
"state.form.warningScopeRows[$index].is_required"
placeholder=
"请选择"
style=
"flex: 1"
>
<el-option
v-for=
"(value, key) in tableSelOptions"
:key=
"key"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</el-form-item>
</div>
<div
v-else-if=
"header.prop == 'is_linkage'"
>
<el-form-item
:prop=
"`[$
{$index}].is_linkage`" :rules="tableRules.is_linkage">
<el-select
v-model=
"state.form.warningScopeRows[$index].is_linkage"
placeholder=
"请选择"
style=
"flex: 1"
>
<el-option
v-for=
"(value, key) in tableSelOptions"
:key=
"key"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</el-form-item>
</div>
</
template
>
</el-table-column>
</el-table>
<el-popover
v-if=
"inputRef?.length > 0"
:virtual-ref=
"inputRef?.[active_index]"
:visible=
"visible"
popper-class=
"cascader-operation"
placement=
"bottom-start"
>
<div
class=
"filter-first-tree-lists"
@
mousedown.prevent=
""
v-if=
"active_row"
>
<ul
class=
"bg-scroll"
ref=
"first_options_lists"
v-show=
"firstOptions.length > 0"
>
<li
v-for=
"data in firstOptions"
:key=
"data"
:class=
"{
active: active_row.indicator_scope == data.label,
}"
>
<div
class=
"first-label-main"
@
click=
"chooseTreeFirst(active_index, data)"
>
<div
class=
"tree-label"
v-html=
"data.label_html"
></div>
<div
class=
"tree-icon"
>
<bg-icon
style=
"font-size: 15px; color: #404a62"
class=
"is-loading"
:class=
"{ 'loading-show': data.isLoading }"
icon=
"#bg-ic-loading"
></bg-icon>
<bg-icon
style=
"font-size: 13px; color: #404a62"
icon=
"#bg-ic-arrow-right"
></bg-icon>
</div>
</div>
</li>
</ul>
<ul
v-show=
"firstOptions.length == 0"
>
<li
class=
"no-data"
>
{{
active_row.input_indicator_tag
? firstOptionsLoading
? "查询中"
: "未查询到相关指标范围数据"
: "请输入查询"
}}
</li>
</ul>
<ul
class=
"bg-scroll"
v-show=
"lastOptions?.length > 0"
>
<li
v-for=
"child in lastOptions"
:key=
"child"
@
click=
"chooseTreeLast(child, active_index)"
:class=
"{ active: active_row.indicator_tag == child }"
>
{{ child }}
</li>
</ul>
<ul
v-show=
"active_row.indicator_scope && lastOptions?.length == 0"
>
<li
class=
"no-data"
>
{{ lastOptionsLoading ? "查询中" : "未查询到相关指标标签" }}
</li>
</ul>
</div>
</el-popover>
</el-form>
</template>
<
script
setup
>
import
{
reactive
,
watch
,
nextTick
,
computed
,
ref
,
onMounted
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
const
props
=
defineProps
({
indicator_expression
:
{
type
:
String
,
default
:
""
,
},
warningScopeRows
:
{
type
:
Array
,
default
:
()
=>
[],
},
});
// 是否是必填和是否联动下拉数据
const
tableSelOptions
=
[
"
否
"
,
"
是
"
];
// 表格表头
const
warningScopeHeaders
=
[
{
prop
:
"
key
"
,
label
:
"
变量名称
"
,
width
:
100
,
},
{
prop
:
"
indicator_tag
"
,
label
:
"
指标标签
"
,
},
{
prop
:
"
cname
"
,
label
:
"
中文名称
"
,
},
{
prop
:
"
is_required
"
,
label
:
"
是否必填
"
,
width
:
150
,
},
{
prop
:
"
is_linkage
"
,
label
:
"
是否联动
"
,
width
:
150
,
},
];
// 表单数据
const
state
=
reactive
({
form
:
{
warningScopeRows
:
[],
},
});
// 表单验证
const
tableRules
=
{
input_indicator_tag
:
[{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
}],
cname
:
[{
required
:
true
,
message
:
"
请输入
"
,
trigger
:
"
blur
"
}],
};
// 获取到的第一级指标范围基础数据集合
const
dataTreeDefault
=
ref
([]);
// 是否是输入触发
const
isInput
=
ref
(
false
);
const
first_options_lists
=
ref
(
null
);
// 指标输入框元素集合
const
inputRef
=
ref
(
null
);
// 监听父组件传过来的指标表达式
watch
(
()
=>
props
.
indicator_expression
,
async
(
n
)
=>
{
await
nextTick
();
let
tableCreateKeys
=
n
?.
match
(
/
\$(
.+
?)\$
/g
)
||
[];
let
arr
=
[];
tableCreateKeys
.
forEach
((
e
)
=>
{
let
i
=
state
.
form
.
warningScopeRows
.
findIndex
((
el
)
=>
el
.
key
==
e
);
if
(
i
>=
0
)
{
arr
[
i
]
=
state
.
form
.
warningScopeRows
[
i
];
}
else
{
arr
.
push
({
key
:
e
,
input_indicator_tag
:
""
,
indicator_scope
:
""
,
indicator_tag
:
""
,
oldQuery
:
""
,
cname
:
""
,
is_required
:
1
,
is_linkage
:
0
,
});
}
});
state
.
form
.
warningScopeRows
=
arr
;
}
);
// 当前操作input下标
const
active_index
=
ref
(
""
);
// 计算:当前操作input所在行数据源
const
active_row
=
computed
(()
=>
{
if
(
active_index
.
value
===
""
)
return
null
;
return
state
.
form
.
warningScopeRows
[
active_index
.
value
];
});
// 下拉是否可见
const
visible
=
ref
(
false
);
// 第一层下拉
const
firstOptions
=
ref
([]);
// 第一层下拉加载动画
const
firstOptionsLoading
=
ref
(
false
);
// 最后一层下拉
const
lastOptions
=
ref
([]);
// 最后一层的下拉加载动画
const
lastOptionsLoading
=
ref
(
false
);
// 计算:根据聚焦的input 获取当前查询的关键词
const
query
=
computed
(()
=>
{
return
(
index
)
=>
{
const
{
input_indicator_tag
,
oldQuery
}
=
state
.
form
.
warningScopeRows
[
index
];
return
inputType
.
value
?
input_indicator_tag
:
oldQuery
;
};
});
// 选择第一级,获取第二级数据
const
chooseTreeFirst
=
(
index
,
data
,
isInfo
=
false
)
=>
{
lastOptionsLoading
.
value
=
true
;
let
i
=
""
;
// 是否是父组件传过来的默认展示数据
if
(
!
isInfo
)
{
inputRef
.
value
[
index
].
focus
();
i
=
firstOptions
.
value
.
findIndex
((
e
)
=>
e
.
label
==
data
.
label
);
firstOptions
.
value
[
i
].
isLoading
=
true
;
state
.
form
.
warningScopeRows
[
index
].
indicator_tag
=
""
;
state
.
form
.
warningScopeRows
[
index
].
indicator_scope
=
data
.
label
;
lastOptions
.
value
=
[];
}
const
params
=
{
label_name
:
data
.
label
,
};
axios
.
get
(
"
/v1/api/prometheus
"
,
{
params
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
lastOptions
.
value
=
res
.
data
.
data
?.
list
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
})
.
finally
(()
=>
{
lastOptionsLoading
.
value
=
false
;
if
(
i
===
""
)
return
;
firstOptions
.
value
[
i
].
isLoading
=
false
;
});
};
// 获取第一级数据
const
getDataTreeLevelFirst
=
()
=>
{
axios
.
get
(
"
/v1/api/prometheus
"
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
dataTreeDefault
.
value
=
res
.
data
.
data
.
list
.
map
((
e
)
=>
{
return
{
label
:
e
,
isLoading
:
false
,
};
})
||
[];
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
for
(
let
i
=
0
;
i
<
1000
;
i
++
)
{
dataTreeDefault
.
value
.
push
({
label
:
"
total
"
+
i
,
value
:
"
total
"
+
i
,
});
}
};
let
timer
=
null
;
const
inputType
=
ref
(
false
);
const
TreeFilter
=
async
(
index
)
=>
{
const
{
input_indicator_tag
}
=
active_row
.
value
;
// 如果没有输入,或者清空输入,则清除已选中的所有东西和所有下拉数据,并返回
if
(
input_indicator_tag
==
""
)
{
lastOptions
.
value
=
[];
state
.
form
.
warningScopeRows
[
index
].
indicator_scope
=
""
;
state
.
form
.
warningScopeRows
[
index
].
indicator_tag
=
""
;
state
.
form
.
warningScopeRows
[
index
].
oldQuery
=
""
;
return
;
}
let
q
=
query
.
value
(
index
);
// 提升性能问题使用for循环遍历
for
(
let
i
=
0
;
i
<
dataTreeDefault
.
value
.
length
;
i
++
)
{
// 不符合直接跳出当次循环
if
(
!
dataTreeDefault
.
value
[
i
].
label
.
includes
(
q
))
continue
;
firstOptions
.
value
.
push
({
...
dataTreeDefault
.
value
[
i
],
// 高亮显示和输入匹配的项
label_html
:
dataTreeDefault
.
value
[
i
].
label
.
replaceAll
(
q
,
`<span class='mate-str'>
${
q
}
</span>`
),
});
}
// 如果第一级下拉没有数据,则隐藏第二级下拉,并清除当前现在的指标范围
if
(
firstOptions
.
value
.
length
==
0
)
{
lastOptions
.
value
=
[];
state
.
form
.
warningScopeRows
[
index
].
indicator_scope
=
""
;
}
// 结束查询中
firstOptionsLoading
.
value
=
false
;
// 查询后第一级滚动条滚动到顶部
first_options_lists
.
value
.
scrollTop
=
0
;
};
// 输入模糊查询数据
const
inputLabel
=
async
(
index
,
type
)
=>
{
visible
.
value
=
false
;
firstOptions
.
value
=
[];
await
nextTick
();
active_index
.
value
=
index
;
// 记录当前是聚焦还是输入
inputType
.
value
=
type
;
visible
.
value
=
true
;
// 第一级显示查询中
firstOptionsLoading
.
value
=
true
;
// 用户输入节流
if
(
timer
)
{
clearTimeout
(
timer
);
timer
=
null
;
}
timer
=
setTimeout
(
()
=>
{
// 过滤下拉数据
TreeFilter
(
index
);
},
// 如果是聚集input的时候不需要节流,输入节流
type
?
500
:
0
);
};
// 失去焦点是隐藏popper
const
blurInput
=
(
index
)
=>
{
// 判断是聚焦失去焦点还是输入后失去焦点,输入后失去焦点记录输入的内容,聚焦失去焦点还是使用之前的记录
state
.
form
.
warningScopeRows
[
index
].
oldQuery
=
query
.
value
(
index
);
// 隐藏popper
visible
.
value
=
false
;
};
// 选择范围中的属性
const
chooseTreeLast
=
(
last
,
index
)
=>
{
state
.
form
.
warningScopeRows
[
index
].
input_indicator_tag
=
last
;
state
.
form
.
warningScopeRows
[
index
].
indicator_tag
=
last
;
isInput
.
value
=
false
;
inputRef
.
value
[
index
].
blur
();
};
// form表单元素
const
form_ref
=
ref
(
null
);
// 提交操作调用
const
Submit
=
async
()
=>
{
let
form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
form_ref
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
let
isFull
=
true
;
try
{
state
.
form
.
warningScopeRows
.
forEach
((
e
,
i
)
=>
{
if
(
e
.
indicator_scope
==
""
||
e
.
indicator_tag
==
""
)
{
throw
`第
${
i
+
1
}
条数据的指标没有选择!`
;
}
});
}
catch
(
e
)
{
if
(
e
)
{
ElMessage
.
error
(
e
);
isFull
=
false
;
}
}
return
form_valid
&&
isFull
;
};
// 监听编辑的原数据,并显示
watch
(
()
=>
props
.
warningScopeRows
,
(
n
)
=>
{
state
.
form
.
warningScopeRows
=
n
?.
map
((
e
,
i
)
=>
{
chooseTreeFirst
(
i
,
{
label
:
e
.
indicator_scope
},
true
);
return
{
key
:
e
.
key
,
input_indicator_tag
:
e
.
indicator_tag
,
indicator_scope
:
e
.
indicator_scope
,
indicator_tag
:
e
.
indicator_tag
,
oldQuery
:
e
.
indicator_scope
,
cname
:
e
.
cname
,
is_required
:
e
.
is_required
,
is_linkage
:
e
.
is_linkage
,
};
})
||
[];
},
{
deep
:
true
,
immediate
:
true
,
}
);
// 获取第一级指标范围列表
onMounted
(()
=>
{
getDataTreeLevelFirst
();
});
defineExpose
({
Submit
,
form
:
state
.
form
,
form_ref
,
});
</
script
>
<
style
lang=
"scss"
scoped
>
.indictor-tag
{
width
:
100%
;
}
</
style
>
<
style
lang=
"scss"
>
.cascader-operation
{
width
:
auto
!
important
;
padding
:
0
!
important
;
min-width
:
180px
!
important
;
position
:
relative
;
min-height
:
204px
;
.el-scrollbar
{
border-radius
:
0
;
}
.filter-first-tree-lists
{
height
:
240px
;
display
:
flex
;
min-width
:
100%
;
content-visibility
:
auto
;
contain-intrinsic-size
:
34px
;
ul
{
min-width
:
180px
;
height
:
100%
;
&
:not
(
:first-child
)
{
border-left
:
1px
solid
#ddd
;
}
li
{
padding-left
:
20px
;
line-height
:
34px
;
// max-width: 400px;
word-break
:
break-all
;
transition
:
all
300ms
;
font-size
:
12px
;
&
:hover
{
background-color
:
#f1f1f1
;
}
cursor
:
pointer
;
&
.active
{
font-weight
:
bold
;
background-color
:
#f1f1f1
;
}
}
}
.first-label-main
{
padding-right
:
48px
;
position
:
relative
;
.tree-label
{
width
:
100%
;
}
.tree-icon
{
width
:
40px
;
height
:
100%
;
position
:
absolute
;
right
:
0
;
top
:
0
;
display
:
flex
;
align-items
:
center
;
svg
{
width
:
20px
;
}
.is-loading
{
animation
:
rotate
3s
linear
infinite
;
opacity
:
0
;
&
.loading-show
{
opacity
:
1
;
}
}
@keyframes
rotate
{
from
{
transform
:
rotate
(
0deg
);
}
to
{
transform
:
rotate
(
360deg
);
}
}
}
}
.no-data
{
width
:
100%
;
height
:
100%
;
display
:
flex
;
align-items
:
center
;
justify-content
:
center
;
color
:
gray
;
box-sizing
:
border-box
;
padding
:
0
20px
;
}
}
}
.mate-str
{
font-weight
:
bold
;
}
</
style
>
src/page/main/forewarning/list/detail/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/list/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.keyword"
placeholder=
"请输入预警点/分类/指标"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"batchPush"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-edit"
></bg-icon>
批量推送
</el-button>
<el-button
type=
"default"
@
click=
"batchClose"
>
批量关闭
</el-button>
<span
class=
"header_info"
>
已选择
<span
style=
"color: #202531; font-weight: bold"
>
{{
state
.
selected
.
length
}}
</span>
项
</span>
<span
class=
"header_info can_click_text"
@
click=
"clearSelected"
>
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
风险等级
</span>
<el-select
v-model=
"filter.risk_level"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(value, key, index) in riskLevels"
:key=
"'riskLevels' + index"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
状态
</span>
<el-select
v-model=
"filter.status"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(value, key, index) in statusOptions"
:key=
"'stateOptions' + index"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
预警时间
</span>
<el-date-picker
style=
"width: 400px"
v-model=
"filter.time"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
/>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"dataTable"
:headers=
"headers"
:rows=
"tableRows"
@
selectAc=
"selectRows"
:selectable=
"selectable"
:isIndex=
"true"
:select=
"true"
:stripe=
"true"
>
<
template
v-slot:alert_point=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"goDetail(row)"
>
{{
row
.
alert_point
}}
</span>
</
template
>
<
template
v-slot:risk_level=
"{ row }"
>
{{
riskLevels
[
row
.
risk_level
]
}}
</
template
>
<
template
v-slot:current_value=
"{ row }"
>
{{
row
.
current_value
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
</
template
>
<
template
v-slot:warn_threshold=
"{ row }"
>
{{
row
.
alert_condition
.
thresholds_min
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
-
{{
row
.
alert_condition
.
thresholds_max
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
</
template
>
<
template
v-slot:alert_time=
"{ row }"
>
{{
dateStringToDate
(
row
.
alert_time
)
}}
</
template
>
<
template
v-slot:last_push_time=
"{ row }"
>
{{
dateStringToDate
(
row
.
last_push_time
)
}}
</
template
>
<
template
#status
="{
row
}"
>
<span
:class=
"`circle status-$
{row.status}`">
</span>
{{
statusOptions
[
row
.
status
]
}}
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:page_size=
"3"
:tableData=
"tableRows"
>
<bg-table-btn
:disabled=
"row.status != 2"
@
click=
"pushWarning(row)"
>
推送提醒
</bg-table-btn>
<bg-table-btn
:disabled=
"row.status != 2"
@
click=
"closeWarning(row)"
>
关闭预警
</bg-table-btn>
</bg-table-btns2>
</
template
>
</bg-table>
</div>
<bg-pagination
:page=
"filter.page"
:size=
"filter.size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
<!-- 推送提醒 -->
<el-dialog
title=
"推送提醒"
v-model=
"pushDialog"
width=
"780px"
:before-close=
"cancelPushDialog"
>
<div
class=
"warning_info"
>
<bg-icon
style=
"font-size: 12px; color: #a9b1c7; margin-right: 8px; vertical-align: middle"
icon=
"#bg-ic-s-circle-tips"
></bg-icon
>
该推送为临时推送,可调整推送人员,仅本次有效!如固定通知人员,则前往【预警规则设置】调整预警内容
</div>
<ManualDistributionForm
ref=
"manual_distribution_form"
:noElLabel=
"false"
methodLabel=
"预警工单推送"
:history=
"state.history"
/>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"cancelPushDialog"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"pushConfirm"
>
确定
</el-button>
</div>
</
template
>
</el-dialog>
<!-- 关闭提醒 -->
<el-dialog
class=
"dialog_box"
title=
"关闭预警"
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-page_size
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>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"cancelCloseWarningDialog"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"confirmClose"
>
确定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
ManualDistributionForm
from
"
@/components/manual-distribution/form.vue
"
;
import
{
GetRuleTypeOptions
,
dateStringToDate
}
from
"
@/components/env
"
;
const
router
=
useRouter
();
const
bgForm
=
ref
(
null
);
const
dataTable
=
ref
(
null
);
const
closeForm
=
ref
(
null
);
const
userTable
=
ref
(
null
);
const
manual_distribution_form
=
ref
(
null
);
const
statusOptions
=
{
""
:
"
全部
"
,
1
:
"
已恢复
"
,
2
:
"
未恢复
"
,
3
:
"
已关闭
"
,
};
const
ruleTypeOptions
=
ref
({});
const
state
=
reactive
({
riskLevels
:
{
""
:
"
全部
"
,
1
:
"
低风险
"
,
2
:
"
一般风险
"
,
3
:
"
较大风险
"
,
4
:
"
重大风险
"
,
},
// 风险等级
headers
:
[
{
label
:
"
预警点
"
,
prop
:
"
alert_point
"
,
width
:
180
,
},
{
label
:
"
预警时间
"
,
prop
:
"
alert_time
"
,
width
:
160
,
},
{
label
:
"
预警分类
"
,
prop
:
"
class_parent_name
"
,
},
{
label
:
"
预警指标
"
,
prop
:
"
class_name
"
,
},
{
label
:
"
风险等级
"
,
prop
:
"
risk_level
"
,
},
{
label
:
"
当前报警值
"
,
prop
:
"
current_value
"
,
},
{
label
:
"
预警阈值
"
,
prop
:
"
warn_threshold
"
,
},
{
label
:
"
通知人数
"
,
prop
:
"
notification_count
"
,
width
:
80
,
},
{
label
:
"
推送次数
"
,
prop
:
"
push_count
"
,
width
:
80
,
},
{
label
:
"
最后推送时间
"
,
prop
:
"
last_push_time
"
,
width
:
160
,
},
{
label
:
"
状态
"
,
prop
:
"
status
"
,
width
:
90
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
180
,
fixed
:
"
right
"
,
},
],
tableRows
:
[],
// 表格数据
selected
:
[],
//选择数据
tableTotal
:
0
,
// 表格数据条数
filter
:
{
risk_level
:
""
,
// 风险等级
status
:
""
,
// 状态
time
:
[],
keyword
:
""
,
page
:
1
,
page_size
:
10
,
},
// 表格筛选项
actionRow
:
null
,
// 当前操作的数据
closeWarningDialog
:
false
,
// 删除弹窗
closeFormData
:
{
close_notes
:
""
,
close_remind
:
false
,
},
closeRules
:
{
close_notes
:
[{
required
:
true
,
message
:
"
请输入关闭备注
"
,
trigger
:
"
blur
"
}],
},
history
:
null
,
pushDialog
:
false
,
pushType
:
0
,
// 1-单条推送 2-批量推送
closeType
:
0
,
// 1-单条推送 2-批量推送
});
const
userTableFlag
=
computed
(()
=>
{
return
!!
state
.
pushDialog
;
});
const
selectRows
=
(
data
)
=>
{
state
.
selected
=
data
.
selection
;
};
const
clearSelected
=
()
=>
{
dataTable
.
value
.
clearTable
();
};
// 清空
const
batchClose
=
()
=>
{
if
(
!
state
.
selected
||
state
.
selected
.
length
==
0
)
{
ElMessage
.
error
(
"
请先勾选要关闭的预警数据
"
);
return
;
}
state
.
closeType
=
2
;
state
.
closeWarningDialog
=
true
;
};
// 批量关闭
const
goDetail
=
(
row
)
=>
{
router
.
push
(
`/forewarning/list/detail?id=
${
row
.
id
}
`
);
};
// 查看详情
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
keyword
=
val
;
changePage
(
1
);
};
// 表格关键字筛选
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 查询按钮
const
filterClear
=
()
=>
{
state
.
filter
=
{
warning_type
:
""
,
// 预警类型
warning_target
:
""
,
// 预警指标
risk_level
:
""
,
// 风险等级
status
:
""
,
// 状态
time
:
[],
keyword
:
""
,
page
:
1
,
page_size
:
10
,
};
changePage
(
1
);
};
// 重置筛选项
const
selectable
=
(
row
,
index
)
=>
{
return
row
.
status
===
2
;
};
const
getTableRows
=
()
=>
{
let
[
start_time
=
""
,
end_time
=
""
]
=
state
.
filter
.
time
||
[];
let
params
=
{
...
state
.
filter
,
start_time
,
end_time
,
};
Reflect
.
deleteProperty
(
params
,
"
time
"
);
axios
.
get
(
"
/v1/api/alert/list
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
let
{
list
,
total_count
}
=
res
.
data
.
data
;
state
.
tableRows
=
list
||
[];
state
.
tableTotal
=
total_count
;
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
// 获取表格数据
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
page_size
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
batchPush
=
()
=>
{
if
(
!
state
.
selected
||
state
.
selected
.
length
==
0
)
{
ElMessage
.
error
(
"
请先勾选要推送的数据
"
);
return
;
}
state
.
pushType
=
2
;
state
.
history
=
null
;
state
.
pushDialog
=
true
;
};
// 批量推送
const
pushWarning
=
(
row
)
=>
{
state
.
actionRow
=
row
;
state
.
pushType
=
1
;
state
.
pushDialog
=
true
;
let
alert_rules_id
=
row
.
alert_rules_id
;
axios
.
get
(
`/v1/api/alert_rules/list`
,
{
params
:
{
id
:
alert_rules_id
}
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
if
(
!
res
.
data
.
data
.
list
||
res
.
data
.
data
.
list
.
length
==
0
)
return
;
state
.
history
=
{
method
:
res
.
data
.
data
.
list
[
0
].
notify_method
||
[],
lists
:
res
.
data
.
data
.
list
[
0
].
notify_recipients
?.
map
((
e
)
=>
{
return
{
user_id
:
e
.
system_account
,
user_name
:
e
.
user_name
,
phone
:
e
.
phone
,
};
})
||
[],
};
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
// 推送提醒
const
cancelPushDialog
=
()
=>
{
state
.
pushDialog
=
false
;
};
// 预警推送弹窗取消按钮:重置表单
const
pushConfirm
=
async
()
=>
{
const
manual_distribution_form_valid
=
await
manual_distribution_form
.
value
.
Submit
();
if
(
!
manual_distribution_form_valid
)
return
;
const
{
method
,
lists
}
=
manual_distribution_form
.
value
.
form
||
{};
let
params
=
{
ids
:
state
.
pushType
==
1
?
[
+
state
.
actionRow
.
id
]
:
state
.
selected
.
map
((
e
)
=>
+
e
.
id
),
notify_method
:
method
||
[],
notify_recipients
:
lists
?.
map
((
e
)
=>
{
return
{
system_account
:
e
.
user_id
,
user_name
:
e
.
user_name
,
phone
:
e
.
phone
,
};
}),
};
axios
.
put
(
"
/v1/api/alert/batch/push
"
,
params
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
推送成功
"
);
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
})
.
finally
((
e
)
=>
{
cancelPushDialog
();
clearSelected
();
changePage
(
1
);
});
};
const
closeWarning
=
(
row
)
=>
{
state
.
actionRow
=
row
;
state
.
closeType
=
1
;
state
.
closeWarningDialog
=
true
;
console
.
log
(
"
关闭预警
"
);
};
// 关闭预警
const
cancelCloseWarningDialog
=
()
=>
{
closeForm
.
value
.
resetFields
();
state
.
closeWarningDialog
=
false
;
};
// 关闭预警弹窗取消按钮:重置表单
const
confirmClose
=
()
=>
{
closeForm
.
value
.
validate
((
valid
)
=>
{
if
(
valid
)
{
let
params
=
{
ids
:
state
.
closeType
==
1
?
[
+
state
.
actionRow
.
id
]
:
state
.
selected
.
map
((
e
)
=>
+
e
.
id
),
close_remark
:
state
.
closeFormData
.
close_notes
,
defer_push
:
state
.
closeFormData
.
close_remind
?
1
:
0
,
};
axios
.
put
(
"
/v1/api/alert/batch/close
"
,
params
)
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
关闭预警操作成功
"
);
}
else
{
ElMessage
.
error
(
res
.
dta
.
msg
);
}
})
.
finally
((
e
)
=>
{
cancelCloseWarningDialog
();
clearSelected
();
changePage
(
1
);
});
}
});
};
// 关闭预警弹窗确定按钮:提交表单
const
getRuleTypeOptions
=
async
()
=>
{
ruleTypeOptions
.
value
=
await
GetRuleTypeOptions
();
getTableRows
();
};
onBeforeMount
(()
=>
{
getRuleTypeOptions
();
});
const
{
headers
,
tableRows
,
tableTotal
,
filter
,
riskLevels
,
stateOptions
,
closeWarningDialog
,
closeFormData
,
closeRules
,
pushDialog
,
}
=
toRefs
(
state
);
</
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%
;
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
height
:
calc
(
100%
-
70px
);
width
:
100%
;
padding
:
0
16px
;
.table
{
max-height
:
calc
(
100%
-
64px
);
.circle
{
display
:
inline-block
;
width
:
6px
;
height
:
6px
;
border-radius
:
3px
;
transform
:
translateY
(
-2px
);
}
.status
{
$statusObj
:
(
1
:
#48ad97
,
3
:
#9e9e9e
,
2
:
#3759be
,
);
@each
$status
,
$color
in
$statusObj
{
&
-
#{
$status
}
{
background-color
:
$color
;
}
}
}
}
}
}
.bg_form
{
width
:
100%
;
box-sizing
:
border-box
;
.el-form-item
{
margin-bottom
:
16px
;
:deep
()
.el-form-item__label
{
line-height
:
36px
;
height
:
36px
;
}
.el-form-item__content
{
width
:
100%
;
.el-textarea
{
:deep
()
.el-input__count
{
bottom
:
6px
;
right
:
4px
;
font-family
:
Roboto-Regular
;
color
:
#a9b1c7
;
}
}
}
}
}
:deep
()
.dialog_box
{
.el-dialog__body
{
padding-bottom
:
0
;
}
}
}
.no-el-label
{
:deep
(
.el-form-item__content
)
{
text-align
:
left
;
margin-left
:
10px
!
important
;
.el-checkbox__label
{
line-height
:
18px
;
}
}
}
</
style
>
src/page/main/forewarning/rule-set/add/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/rule-set/detail/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/rule-set/edit/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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
>
src/page/main/forewarning/rule-set/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"detail_container"
>
<bg-breadcrumb></bg-breadcrumb>
<div
class=
"main_container"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.keyword"
inputWidth=
"380px"
placeholder=
"请输入预警规则名称/预警对象/预警分类/预警指标"
>
<template
v-slot:left_action
>
<div
class=
"apaas_button"
>
<el-button
type=
"primary"
@
click=
"addRule"
>
<bg-icon
style=
"font-size: 12px; color: #fff; margin-right: 8px"
icon=
"#bg-ic-add"
></bg-icon>
新增
</el-button>
<el-button
type=
"default"
@
click=
"batchDelete"
>
批量删除
</el-button>
<span
class=
"header_info"
>
已选择
<span
style=
"color: #202531; font-weight: bold"
>
{{
state
.
selected
.
length
}}
</span>
项
</span>
<span
class=
"header_info can_click_text"
@
click=
"clearSelected"
>
清空
</span>
</div>
</
template
>
<
template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
通知方式
</span>
<el-select
v-model=
"filter.notify_method"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in noticeTypes"
:key=
"'noticeTypes' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
启用状态
</span>
<el-select
v-model=
"filter.is_enabled"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(item, index) in stateOptions"
:key=
"'stateOptions' + index"
:label=
"item.name"
:value=
"item.value"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
时段
</span>
<el-date-picker
style=
"width: 300px"
v-model=
"filter.time"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"至"
start-placeholder=
"开始日期"
end-placeholder=
"结束日期"
/>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table bg-scroll"
>
<bg-table
ref=
"dataTable"
:headers=
"headers"
:rows=
"tableRows"
@
selectAc=
"selectRows"
:selectable=
"selectable"
:isIndex=
"true"
:select=
"true"
:stripe=
"true"
>
<
template
v-slot:metric_name=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"goDetail(row)"
>
{{
row
.
metric_name
}}
</span>
</
template
>
<
template
v-slot:notify_method=
"{ row }"
>
{{
row
.
notify_method
.
map
((
e
)
=>
METHODS
[
e
]).
join
(
"
,
"
)
}}
</
template
>
<
template
v-slot:notify_recipients=
"{ row }"
>
{{
row
.
notify_recipients
.
length
}}
</
template
>
<
template
#is_enabled
="{
row
}"
>
<bg-switch
@
click=
"stateChange(row)"
:labels=
"['否', '是']"
:values=
"[2, 1]"
v-model=
"row.is_enabled"
></bg-switch>
</
template
>
<
template
v-slot:created_at=
"{ row }"
>
{{
dateStringToDate
(
row
.
created_at
)
}}
</
template
>
<
template
v-slot:action=
"{ row }"
>
<bg-table-btns2
:limit=
"3"
:tableData=
"tableRows"
>
<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>
</div>
<bg-pagination
:page=
"filter.page"
:size=
"filter.size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
<!-- 删除 -->
<el-dialog
class=
"dialog_box"
title=
"删除"
v-model=
"delDialog"
width=
"420px"
>
<div>
确定要删除吗?
</div>
<
template
v-slot:footer
>
<div
class=
"apaas_button"
>
<el-button
type=
"default"
@
click=
"delDialog = false"
>
取消
</el-button>
<el-button
type=
"primary"
@
click=
"delConfirm"
>
确定
</el-button>
</div>
</
template
>
</el-dialog>
</div>
</template>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
Search
}
from
"
@element-plus/icons-vue
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
{
dateStringToDate
}
from
"
@/components/env
"
;
const
METHODS
=
{
dingtalk
:
"
钉钉
"
,
sms
:
"
短信
"
,
};
const
router
=
useRouter
();
const
dataTable
=
ref
(
null
);
const
state
=
reactive
({
noticeTypes
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
钉钉
"
,
value
:
"
dingtalk
"
,
},
{
name
:
"
短信
"
,
value
:
"
sms
"
,
},
],
stateOptions
:
[
{
name
:
"
全部
"
,
value
:
""
,
},
{
name
:
"
启用
"
,
value
:
1
,
},
{
name
:
"
停用
"
,
value
:
2
,
},
],
// 状态
headers
:
[
{
label
:
"
预警规则名称
"
,
prop
:
"
metric_name
"
,
width
:
200
,
},
{
label
:
"
预警分类
"
,
prop
:
"
class_parent_name
"
,
},
{
label
:
"
预警对象
"
,
prop
:
"
class_name
"
,
},
{
label
:
"
预警指标
"
,
prop
:
"
metric_config_name
"
,
},
{
label
:
"
通知方式
"
,
prop
:
"
notify_method
"
,
},
{
label
:
"
通知人数
"
,
prop
:
"
notify_recipients
"
,
},
{
label
:
"
是否启用
"
,
prop
:
"
is_enabled
"
,
},
{
label
:
"
创建人
"
,
prop
:
"
created_by
"
,
},
{
label
:
"
创建时间
"
,
prop
:
"
created_at
"
,
width
:
160
,
},
{
label
:
"
操作
"
,
prop
:
"
action
"
,
width
:
136
,
fixed
:
"
right
"
,
},
],
tableRows
:
[],
// 表格数据
selected
:
[],
//选择数据
tableTotal
:
0
,
// 表格数据条数
filter
:
{
notify_method
:
""
,
// 通知方式
is_enabled
:
""
,
// 状态
time
:
[],
keyword
:
""
,
page
:
1
,
limit
:
10
,
},
// 表格筛选项
actionRow
:
null
,
// 当前操作的数据
delDialog
:
false
,
// 删除弹窗
delType
:
0
,
// 1-单条删除 2-批量删除
});
const
selectRows
=
(
data
)
=>
{
state
.
selected
=
data
.
selection
;
};
const
clearSelected
=
()
=>
{
dataTable
.
value
.
clearTable
();
};
// 清空
const
batchDelete
=
()
=>
{
console
.
log
(
"
批量删除
"
);
if
(
!
state
.
selected
||
state
.
selected
.
length
==
0
)
{
ElMessage
.
error
(
"
请先勾选要删除的数据
"
);
return
;
}
state
.
delType
=
2
;
state
.
delDialog
=
true
;
};
// 批量删除
const
goDetail
=
(
row
)
=>
{
console
.
log
(
"
去详情
"
);
router
.
push
({
path
:
"
/forewarning/rule-set/detail
"
,
query
:
{
id
:
row
.
id
,
},
});
};
// 查看详情
const
changeSearch
=
(
val
)
=>
{
state
.
filter
.
keyword
=
val
;
changePage
(
1
);
};
// 表格关键字筛选
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 查询按钮
const
filterClear
=
()
=>
{
state
.
filter
=
{
notify_method
:
""
,
// 通知方式
is_enabled
:
""
,
// 状态
time
:
""
,
keyword
:
""
,
page
:
1
,
limit
:
10
,
};
changePage
(
1
);
};
// 重置筛选项
const
selectable
=
(
row
,
index
)
=>
{
return
row
.
is_enabled
===
2
;
};
const
getTableRows
=
()
=>
{
let
[
start_time
=
""
,
end_time
=
""
]
=
state
.
filter
.
time
||
[];
let
params
=
{
...
state
.
filter
,
start_time
,
end_time
,
};
Reflect
.
deleteProperty
(
params
,
"
time
"
);
axios
.
get
(
`/v1/api/alert_rules/list`
,
{
params
,
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
tableRows
=
res
.
data
.
data
?.
list
||
[];
state
.
tableTotal
=
res
.
data
.
data
.
total_count
;
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
// 获取表格数据
const
changePage
=
(
page
)
=>
{
state
.
filter
.
page
=
page
;
getTableRows
();
};
// 改变页码
const
changeSize
=
(
size
)
=>
{
state
.
filter
.
limit
=
size
;
changePage
(
1
);
};
// 改变每页条数
const
stateChange
=
({
id
,
is_enabled
})
=>
{
const
params
=
{
id
,
is_enabled
,
};
axios
.
put
(
`/v1/api/alert_rules/is_enabled`
,
params
).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
ElMessage
.
success
(
"
状态修改成功
"
);
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
row
.
state
=
row
.
state
==
1
?
2
:
1
;
}
});
};
const
addRule
=
()
=>
{
router
.
push
({
path
:
`/forewarning/rule-set/add`
,
});
};
// 新增规则
const
editRow
=
(
row
)
=>
{
router
.
push
({
path
:
`/forewarning/rule-set/edit`
,
query
:
{
id
:
row
.
id
,
},
});
};
// 编辑
const
deleteRow
=
(
row
)
=>
{
state
.
actionRow
=
row
;
state
.
delType
=
1
;
state
.
delDialog
=
true
;
};
// 删除
const
delConfirm
=
()
=>
{
let
ids
=
[];
if
(
state
.
delType
==
1
)
{
ids
.
push
(
state
.
actionRow
.
id
);
}
else
{
ids
=
state
.
selected
.
map
((
e
)
=>
{
return
e
.
id
;
});
}
axios
.
delete
(
"
/v1/api/alert_rules
"
,
{
data
:
{
ids
,
},
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
"
200
"
)
{
ElMessage
.
success
(
"
删除成功
"
);
state
.
delDialog
=
false
;
clearSelected
();
changePage
(
1
);
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
// 确定删除
onBeforeMount
(()
=>
{
getTableRows
();
});
const
{
headers
,
tableRows
,
tableTotal
,
filter
,
noticeTypes
,
stateOptions
,
delDialog
}
=
toRefs
(
state
);
</
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%
;
.filter-group
{
.left-filter
{
flex
:
1
;
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
width
:
144px
;
padding-bottom
:
16px
;
.el-button
{
width
:
64px
;
}
}
}
.table_container
{
height
:
calc
(
100%
-
70px
);
width
:
100%
;
padding
:
0
16px
;
.table
{
max-height
:
calc
(
100%
-
64px
);
}
}
}
}
</
style
>
src/page/main/forewarning/rule-set/modules/add-form.vue
deleted
100644 → 0
View file @
dd5821ad
<
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=
"type"
>
<el-button-group>
<el-button
v-for=
"(value, key) in types"
:key=
"key"
:type=
"state.form.type_key == key ? 'primary' : ''"
size=
"small"
@
click=
"changeType(key)"
:disabled=
"isEdit"
>
{{
value
}}
</el-button>
</el-button-group>
</el-form-item>
</div>
<component
ref=
"type_com_ref"
:is=
"typeCom[state.form.type_key]"
:isEdit=
"isEdit"
:form=
"typrFormData"
@
update-duration=
"updateDuration"
></component>
<gap-title
:hasLine=
"true"
title=
"高级配置"
></gap-title>
<div
class=
"add-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"
>
<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>
<div
class=
"add-form-item"
>
<el-form-item
class=
"no-el-label"
label=
""
prop=
"push_method"
>
<div
style=
"width: 100%"
>
<ManualDistributionForm
ref=
"manual_distribution_form"
class=
"manual-distribution-form"
labelWidth=
"120px"
:noElLabel=
"false"
methodLabel=
"预警通知方式"
:history=
"history"
/>
</div>
</el-form-item>
<el-form-item
label=
"消息推送次数"
>
<el-input
style=
"flex: 1"
v-model=
"state.form.push_num"
placeholder=
"请输入消息推送次数"
clearable
>
<
template
#append
>
次
</
template
>
</el-input>
</el-form-item>
<el-form-item
label=
"消息推送频率"
>
<el-input
style=
"flex: 1"
v-model=
"state.form.push_frequency"
placeholder=
"请输入消息推送频率"
clearable
>
<
template
#append
>
分钟
</
template
>
</el-input>
</el-form-item>
<el-form-item
label=
"是否立即启用"
prop=
""
>
<el-switch
v-model=
"state.form.enabled"
inline-prompt
active-text=
"是"
inactive-text=
"否"
:active-value=
"true"
:inactive-value=
"false"
>
</el-switch>
</el-form-item>
</div>
</el-form>
</div>
</template>
<
script
setup
>
import
{
reactive
,
ref
,
shallowReactive
,
computed
,
nextTick
,
watch
}
from
"
vue
"
;
import
gapTitle
from
"
@/components/gap-title.vue
"
;
import
ManualDistributionForm
from
"
@/components/manual-distribution/form.vue
"
;
import
Static
from
"
./static.vue
"
;
import
Custom
from
"
./custom.vue
"
;
import
{
MAX_DAY
}
from
"
@/components/env.js
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
const
props
=
defineProps
({
row
:
{
type
:
Object
,
default
:
null
,
},
});
const
isEdit
=
computed
(()
=>
!!
props
.
row
);
const
history
=
computed
(()
=>
props
.
row
?.
manual_distribution_form
||
null
);
const
typrFormData
=
computed
(()
=>
props
.
row
?.
type_com_ref
||
null
);
const
manual_distribution_form
=
ref
(
null
);
const
typeCom
=
shallowReactive
({
static
:
Static
,
custom
:
Custom
,
});
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
:
""
,
type_key
:
"
static
"
,
time
:
10
,
unit
:
"
s
"
,
inspection_cycle
:
1
,
push_num
:
1
,
push_frequency
:
60
,
enabled
:
true
,
},
rules
:
{
name
:
[{
required
:
true
,
message
:
"
请输入预警规则名称
"
,
trigger
:
"
blur
"
}],
time
:
[{
required
:
true
,
message
:
"
请输入持续时间
"
,
trigger
:
"
blur
"
}],
},
});
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
;
}
};
const
updateDuration
=
(
data
)
=>
{
const
{
duration
,
duration_unit
,
check_period
}
=
data
;
state
.
form
.
time
=
duration
;
state
.
form
.
unit
=
duration_unit
;
state
.
form
.
inspection_cycle
=
check_period
;
};
const
types
=
{
static
:
"
静态阈值
"
,
custom
:
"
自定义
"
,
};
const
changeType
=
async
(
key
)
=>
{
state
.
form
.
type_key
=
key
;
form_ref
.
value
.
clearValidate
();
};
const
timeOptions
=
[
10
,
20
,
60
,
120
,
180
,
300
];
const
inspectionCycleOptions
=
ref
([
1
,
3
,
5
,
10
,
20
]);
const
form_ref
=
ref
(
null
);
const
type_com_ref
=
ref
(
null
);
const
Submit
=
async
()
=>
{
let
form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
form_ref
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
let
type_com_ref_valid
=
await
type_com_ref
.
value
.
Submit
();
let
manual_distribution_form_valid
=
await
manual_distribution_form
.
value
.
Submit
();
if
(
form_valid
&&
type_com_ref_valid
&&
manual_distribution_form_valid
)
{
let
obj
=
{
...
state
.
form
,
type_com_ref
:
type_com_ref
.
value
?.
form
||
{},
manual_distribution_form
:
manual_distribution_form
.
value
?.
form
||
{},
};
return
{
res
:
obj
,
cb
:
()
=>
{
if
(
!
isEdit
.
value
)
{
setTimeout
(()
=>
{
type_com_ref
.
value
.
form_ref
.
resetFields
();
manual_distribution_form
.
value
.
form_ref
.
resetFields
();
form_ref
.
value
.
resetFields
();
},
100
);
}
},
};
}
ElMessage
.
error
(
"
有必填项没有填写
"
);
return
{};
};
watch
(
()
=>
props
.
row
,
(
n
)
=>
{
if
(
!
n
)
return
;
state
.
form
.
name
=
n
.
name
;
state
.
form
.
type_key
=
n
.
type_key
;
state
.
form
.
unit
=
n
.
unit
;
state
.
form
.
time
=
n
.
time
||
10
;
state
.
form
.
inspection_cycle
=
n
.
inspection_cycle
||
1
;
state
.
form
.
push_num
=
n
.
push_num
||
1
;
state
.
form
.
push_frequency
=
n
.
push_frequency
||
60
;
state
.
form
.
enabled
=
n
.
enabled
||
false
;
},
{
deep
:
true
,
immediate
:
true
}
);
defineExpose
({
Submit
,
});
</
script
>
<
style
lang=
"scss"
scoped
>
.add-form
{
:deep
(
.gap-title
)
{
margin-bottom
:
16px
;
}
&
-item
{
max-width
:
1080px
;
width
:
100%
;
padding-left
:
8px
;
.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;
// }
// }
}
: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
;
}
.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
{
:deep
(
.el-form-item__content
)
{
margin-left
:
0
!
important
;
}
}
.manual-distribution-form
{
:deep
(
.el-form-item
)
{
&
:not
(
:last-child
)
{
margin-bottom
:
18px
;
}
}
}
</
style
>
<
style
lang=
"scss"
>
.el-form-item
{
min-height
:
36px
;
label
{
height
:
36px
;
line-height
:
36px
;
}
.el-input__inner
{
min-height
:
34px
;
}
}
</
style
>
src/page/main/forewarning/rule-set/modules/custom.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"custom-form"
>
<el-form
:model=
"state.form"
ref=
"form_ref"
:rules=
"state.rules"
label-width=
"120px"
>
<div
class=
"custom-form-item"
>
<el-form-item
label=
"预警分类"
prop=
"warn_target"
>
<el-input
v-model=
"state.form.warn_target"
placeholder=
"请输入预警分类"
:disabled=
"isEdit"
:maxlength=
"20"
show-word-limit
clearable
@
change=
"changeWarnCustomTarget"
></el-input>
</el-form-item>
<el-form-item
label=
"预警对象"
prop=
"warn_type"
>
<el-input
v-model=
"state.form.warn_type"
placeholder=
"请输入预警对象"
:disabled=
"isEdit"
clearable
:maxlength=
"20"
show-word-limit
@
change=
"changeWarnCustomType"
></el-input>
</el-form-item>
<el-form-item
label=
"预警指标"
prop=
"warn_indicator"
>
<el-input
v-model=
"state.form.warn_indicator"
placeholder=
"请输入预警指标"
:disabled=
"isEdit"
:maxlength=
"30"
show-word-limit
clearable
@
change=
"changeWarnCustomType"
></el-input>
</el-form-item>
</div>
<gap-title
:hasLine=
"true"
title=
"指标表达式"
>
</gap-title>
<div
class=
"custom-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>
</div>
<gap-title
:hasLine=
"true"
title=
"预警规则"
></gap-title>
<div
class=
"custom-form-item"
>
<el-form-item
label=
"预警规则类型"
prop=
"rule_type"
>
<el-select
style=
"flex: 1"
v-model=
"state.form.rule_type"
placeholder=
"请选择"
filterable
@
change=
"changeRuleType"
>
<el-option
v-for=
"(value, key) in ruleTypeOptions"
:key=
"key"
:label=
"value.label"
:value=
"key"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
"风险程度"
prop=
"risk_level"
v-if=
"isEmpty"
>
<el-select
style=
"flex: 1"
v-model=
"state.form.risk_level"
placeholder=
"请选择风险程度"
filterable
>
<el-option
v-for=
"item in riskLevels"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
</el-option>
</el-select>
</el-form-item>
<el-form-item
label=
""
v-else-if=
"state.form.ruleRows.length > 0"
>
<div
class=
"rule-table"
style=
"width: 100%"
>
<el-form
:model=
"state.form.ruleRows"
ref=
"table_form"
:rules=
"state.tableRules"
label-width=
"0"
style=
"width: 100%"
>
<el-table
:data=
"state.form.ruleRows"
stripe
border
>
<el-table-column
v-for=
"header in ruleHeaders"
:prop=
"header.prop"
:key=
"header.prop"
:label=
"header.label"
:width=
"header.width"
>
<template
#default
="
{ $index }">
<div
class=
"warning-threshold"
v-if=
"header.prop == 'warning_threshold'"
>
<el-form-item
:prop=
"`[$
{$index}].from`" :rules="state.tableRules.from($index)" style="flex: 1">
<el-input
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].from"
placeholder=
"请输入"
@
input=
"inputNum($index, 'from')"
@
blur=
"changeWarningThresholdFrom($index)"
>
<template
#append
>
{{
unitMap
}}
</
template
>
</el-input>
</el-form-item>
<span
class=
"to"
>
-
</span>
<el-form-item
label=
""
:prop=
"`${$index}.to`"
:rules=
"state.tableRules.to($index)"
style=
"flex: 1"
>
<el-input
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].to"
placeholder=
"请输入"
clearable
@
input=
"inputNum($index, 'to')"
@
blur=
"changeWarningThresholdTo($index)"
>
<
template
#append
>
{{
unitMap
}}
</
template
>
</el-input>
</el-form-item>
</div>
<div
v-else-if=
"header.prop == 'risk_level'"
>
<el-form-item
label=
""
:prop=
"`[${$index}].risk_level`"
:rules=
"state.tableRules.risk_level"
>
<el-select
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].risk_level"
placeholder=
"请选择风险程度"
>
<el-option
v-for=
"item in riskLevelOptions($index)"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
</el-option>
</el-select>
</el-form-item>
</div>
</template>
</el-table-column>
<el-table-column
prop=
""
label=
"操作"
width=
"150px"
>
<
template
#default
="{
$
index
}"
>
<div
class=
"table-operation"
>
<el-button
link
type=
"primary"
@
click=
"createRule($index)"
:disabled=
"state.form.ruleRows.length >= riskLevels.length"
>
新增
</el-button>
<span
class=
"line"
></span>
<el-button
link
type=
"primary"
@
click=
"removeRule($index)"
:disabled=
"state.form.ruleRows.length == 1"
>
删除
</el-button>
</div>
</
template
>
</el-table-column>
</el-table>
</el-form>
</div>
</el-form-item>
</div>
</el-form>
</div>
</template>
<
script
setup
>
import
{
computed
,
onBeforeMount
,
reactive
,
ref
}
from
"
vue
"
;
import
gapTitle
from
"
@/components/gap-title.vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
GetRuleTypeOptions
,
Empty
}
from
"
@/components/env.js
"
;
const
props
=
defineProps
({
form
:
{
type
:
Object
,
default
:
null
,
},
isEdit
:
{
type
:
Boolean
,
default
:
false
,
},
});
var
validateWarnIndex
=
(
rule
,
value
,
callback
)
=>
{
if
(
value
===
""
)
{
if
(
state
.
form
.
type_key
==
"
static
"
)
{
callback
(
new
Error
(
"
请选择
"
));
}
else
{
callback
(
new
Error
(
"
请输入
"
));
}
}
else
{
callback
();
}
};
const
validateFrom
=
(
rule
,
value
,
callback
,
index
)
=>
{
let
thisRow
=
state
.
form
.
ruleRows
[
index
];
// 如果只有一条数据,并且上限下限都没有填写,则提示错误
if
(
state
.
form
.
ruleRows
.
length
==
1
&&
thisRow
.
from
===
""
&&
thisRow
.
to
==
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
// 当前下限不是第一条数据,并且为空,提示错误
if
(
index
>
0
&&
value
===
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
callback
();
};
const
validateTo
=
(
rule
,
value
,
callback
,
index
)
=>
{
let
thisRow
=
state
.
form
.
ruleRows
[
index
];
// 如果只有一条数据,并且上限下限都没有填写,则提示错误
if
(
state
.
form
.
ruleRows
.
length
==
1
&&
thisRow
.
from
===
""
&&
thisRow
.
to
==
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
// 当前上限不是最后一条数据,并且为空,提示错误
if
(
index
<
state
.
form
.
ruleRows
.
length
-
1
&&
value
===
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
callback
();
};
const
ruleTypeOptions
=
ref
({});
const
state
=
reactive
({
form
:
{
warn_target
:
""
,
warn_type
:
""
,
warn_indicator
:
""
,
indicator_expression
:
""
,
rule_type
:
""
,
ruleRows
:
[],
risk_level
:
""
,
},
rules
:
{
warn_target
:
[{
required
:
true
,
message
:
"
请输入预警分类
"
,
trigger
:
"
blur
"
}],
warn_type
:
[{
required
:
true
,
message
:
"
请输入预警对象
"
,
trigger
:
"
blur
"
}],
rule_type
:
[{
required
:
true
,
message
:
"
请选择预警规则类型
"
,
trigger
:
"
change
"
}],
warn_indicator
:
[{
validator
:
validateWarnIndex
,
trigger
:
"
blur
"
}],
indicator_expression
:
[{
required
:
true
,
message
:
"
请输入预警指标
"
,
trigger
:
"
blur
"
}],
risk_level
:
[{
required
:
true
,
message
:
"
请选择风险程度
"
,
trigger
:
"
change
"
}],
},
tableRules
:
{
from
:
(
index
)
=>
{
return
[{
validator
:
(
rule
,
value
,
callback
)
=>
validateFrom
(
rule
,
value
,
callback
,
index
),
trigger
:
"
blur
"
}];
},
to
:
(
index
)
=>
{
return
[{
validator
:
(
rule
,
value
,
callback
)
=>
validateTo
(
rule
,
value
,
callback
,
index
),
trigger
:
"
blur
"
}];
},
risk_level
:
[{
required
:
true
,
message
:
"
请选择风险程度
"
,
trigger
:
"
change
"
}],
},
});
const
isEmpty
=
computed
(()
=>
{
return
Empty
(
state
.
form
.
rule_type
,
ruleTypeOptions
.
value
);
});
const
changeWarnCustomTarget
=
()
=>
{};
const
changeWarnCustomType
=
()
=>
{};
const
setLimits
=
(
index
)
=>
{
let
rows
=
[...
state
.
form
.
ruleRows
];
rows
.
splice
(
index
,
1
);
return
(
rows
.
map
((
e
)
=>
{
return
{
down
:
+
e
.
from
,
up
:
+
e
.
to
,
};
})
||
[]
);
};
const
inputNum
=
(
index
,
key
)
=>
{
if
(
state
.
form
.
ruleRows
[
index
][
key
]
==
""
)
return
;
if
(
state
.
form
.
ruleRows
[
index
][
key
]
==
"
-
"
)
return
;
state
.
form
.
ruleRows
[
index
][
key
]
=
`
${
state
.
form
.
ruleRows
[
index
][
key
]}
`
.
replace
(
/
[^\-
?
\d
.
]
/g
,
""
)
.
replace
(
/
(\.)
+/
,
"
$1
"
)
.
replace
(
/
(\.\d
+
)\.
+/g
,
"
$1
"
)
.
replace
(
/
(\.
.*
)\.
/g
,
"
$1
"
);
};
const
changeWarningThresholdFrom
=
(
index
)
=>
{
let
{
down
,
up
}
=
limit
.
value
;
let
{
from
,
to
}
=
state
.
form
.
ruleRows
[
index
];
if
(
to
!=
""
&&
from
!==
""
&&
from
>
+
to
)
{
ElMessage
.
error
(
`下限不能大于上限`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
else
if
(
down
!==
""
&&
+
from
<
+
down
)
{
ElMessage
.
error
(
`下限不能小于
${
down
}
`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
else
if
(
up
!=
""
&&
+
from
>
+
up
)
{
ElMessage
.
error
(
`上限不能超过
${
up
}
`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
let
rows
=
setLimits
(
index
);
if
(
rows
.
length
==
0
)
return
;
let
items
=
rows
.
filter
((
e
,
i
)
=>
{
let
isPassDown
=
e
.
down
!==
""
?
+
e
.
down
<=
+
from
:
false
;
let
isLessUp
=
e
.
up
!==
""
?
+
e
.
up
>=
+
from
:
false
;
let
isLessDownAndPassUp
=
e
.
down
!==
""
&&
e
.
up
!==
""
&&
to
!==
""
?
+
from
<
+
e
.
down
&&
+
to
>
+
e
.
up
:
false
;
return
(
isPassDown
&&
isLessUp
)
||
isLessDownAndPassUp
;
});
if
(
items
.
length
>
0
)
{
ElMessage
.
error
(
`该范围已被设置`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
}
};
const
changeWarningThresholdTo
=
(
index
)
=>
{
let
{
down
,
up
}
=
limit
.
value
;
let
{
from
,
to
}
=
state
.
form
.
ruleRows
[
index
];
if
(
from
!=
""
&&
from
!==
""
&&
from
>
+
to
)
{
ElMessage
.
error
(
`下限不能大于上限`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
else
if
(
down
!==
""
&&
+
to
<
+
down
)
{
ElMessage
.
error
(
`下限不能小于
${
down
}
`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
else
if
(
up
!=
""
&&
+
to
>
+
up
)
{
ElMessage
.
error
(
`上限不能超过
${
up
}
`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
let
rows
=
setLimits
(
index
);
if
(
rows
.
length
==
0
)
return
;
let
items
=
rows
.
filter
((
e
,
i
)
=>
{
let
isPassDown
=
e
.
down
!==
""
?
+
e
.
down
<=
+
to
:
false
;
let
isLessUp
=
e
.
up
!==
""
?
+
e
.
up
>=
+
to
:
false
;
let
isLessDownAndPassUp
=
e
.
down
!==
""
&&
e
.
up
!==
""
&&
from
!==
""
?
+
from
<
+
e
.
down
&&
+
to
>
+
e
.
up
:
false
;
return
(
isPassDown
&&
isLessUp
)
||
isLessDownAndPassUp
;
});
if
(
items
.
length
>
0
)
{
ElMessage
.
error
(
`该范围已被设置`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
}
};
const
changeRuleType
=
()
=>
{};
const
form_ref
=
ref
(
null
);
const
table_form
=
ref
(
null
);
const
Submit
=
async
()
=>
{
let
form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
form_ref
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
if
(
isEmpty
.
value
)
{
return
form_valid
;
}
let
table_form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
table_form
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
return
form_valid
&&
table_form_valid
;
};
const
riskLevels
=
ref
([
{
id
:
4
,
name
:
"
重大风险
"
,
},
{
id
:
3
,
name
:
"
较大风险
"
,
},
{
id
:
2
,
name
:
"
一般风险
"
,
},
{
id
:
1
,
name
:
"
低风险
"
,
},
]);
const
riskLevelOptions
=
computed
(()
=>
{
return
(
index
)
=>
{
let
risk_level
=
state
.
form
.
ruleRows
[
index
].
risk_level
;
let
rows
=
state
.
form
.
ruleRows
.
map
((
e
)
=>
e
.
risk_level
);
if
(
risk_level
)
{
let
i
=
rows
.
findIndex
((
e
)
=>
e
==
risk_level
);
rows
.
splice
(
i
,
1
);
}
return
riskLevels
.
value
.
filter
((
e
)
=>
!
rows
.
includes
(
e
.
id
));
};
});
const
unitMap
=
computed
(()
=>
{
return
ruleTypeOptions
.
value
[
state
.
form
.
rule_type
]?.
unit
||
""
;
});
const
limit
=
computed
(()
=>
{
return
(
ruleTypeOptions
.
value
[
state
.
form
.
rule_type
].
limit
||
{
down
:
""
,
up
:
""
,
}
);
});
const
getRuleTypeOptions
=
async
()
=>
{
ruleTypeOptions
.
value
=
await
GetRuleTypeOptions
();
};
const
ruleHeaders
=
[
{
prop
:
"
warning_threshold
"
,
label
:
"
预警阈值
"
,
width
:
"
500px
"
,
},
{
prop
:
"
risk_level
"
,
label
:
"
风险程度
"
,
},
];
const
createRule
=
(
index
=
-
1
)
=>
{
state
.
form
.
ruleRows
.
splice
(
index
+
1
,
0
,
{
from
:
""
,
to
:
""
,
risk_level
:
""
,
});
};
const
removeRule
=
(
index
)
=>
{
state
.
form
.
ruleRows
.
splice
(
index
,
1
);
};
const
info
=
()
=>
{
if
(
!
props
.
form
)
{
createRule
();
return
;
}
state
.
form
.
warn_target
=
props
.
form
.
warn_target
;
state
.
form
.
warn_type
=
props
.
form
.
warn_type
;
state
.
form
.
warn_indicator
=
props
.
form
.
warn_indicator
;
state
.
form
.
indicator_expression
=
props
.
form
.
indicator_expression
;
state
.
form
.
rule_type
=
props
.
form
.
rule_type
;
state
.
form
.
risk_level
=
props
.
form
.
risk_level
;
state
.
form
.
ruleRows
=
props
.
form
?.
ruleRows
?.
map
((
e
)
=>
{
return
{
from
:
e
.
from
,
to
:
e
.
to
,
risk_level
:
e
.
risk_level
,
};
})
||
[];
if
(
state
.
form
.
ruleRows
.
length
==
0
)
{
createRule
();
}
};
const
formatForm
=
computed
(()
=>
{
return
{
...
state
.
form
,
isEmpty
:
isEmpty
.
value
,
};
});
onBeforeMount
(()
=>
{
getRuleTypeOptions
();
info
();
});
defineExpose
({
Submit
,
form
:
formatForm
,
form_ref
,
});
</
script
>
<
style
lang=
"scss"
scoped
>
.custom-form
{
:deep
(
.gap-title
)
{
margin-bottom
:
16px
;
}
&
-item
{
max-width
:
1080px
;
width
:
100%
;
padding-left
:
8px
;
.indicator-expression
{
height
:
300px
;
width
:
100%
;
:deep
(
.vue-ace-editor
)
{
margin-top
:
0
;
}
}
}
}
.warning-threshold
{
display
:
flex
;
align-items
:
center
;
:deep
(
.el-input-group__append
,
.el-input-group__prepend
)
{
border-radius
:
4px
;
border-top-left-radius
:
0
;
border-bottom-left-radius
:
0
;
}
}
.to
{
margin
:
0
16px
;
}
.line
{
width
:
1px
;
height
:
14px
;
background-color
:
#c1c7d7
;
margin
:
0
16px
;
display
:
inline-block
;
}
.rule-table
{
:deep
(
.el-table
thead
th
)
{
background-color
:
#f5f6f9
;
}
}
</
style
>
src/page/main/forewarning/rule-set/modules/gateway.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"gateway-form"
>
<div
class=
"gateway-form-item"
>
<el-form
:model=
"state.form.ruleRows"
ref=
"form_ref"
:rules=
"state.tableRules"
label-width=
"0"
style=
"width: 100%"
>
<el-table
:data=
"state.form.ruleRows"
stripe
border
>
<el-table-column
v-for=
"header in ruleHeaders"
:prop=
"header.prop"
:key=
"header.prop"
:label=
"header.label"
:width=
"header.width"
>
<template
#default
="
{ $index }">
<div
class=
"warning-threshold"
v-if=
"header.prop == 'warning_threshold'"
>
<el-form-item
:prop=
"`[$
{$index}].from`" :rules="state.tableRules.from($index)" style="flex: 1">
<el-input
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].from"
placeholder=
"请输入"
@
input=
"inputNum($index, 'from')"
@
blur=
"changeWarningThresholdFrom($index)"
>
<template
v-if=
"!isEmptyOption"
#append
>
{{
ruleTypeOptions
[
props
.
rule_type
]?.
unit
||
""
}}
</
template
>
</el-input>
</el-form-item>
<span
class=
"to"
>
-
</span>
<el-form-item
label=
""
:prop=
"`${$index}.to`"
:rules=
"state.tableRules.to($index)"
style=
"flex: 1"
>
<el-input
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].to"
placeholder=
"请输入"
clearable
@
input=
"inputNum($index, 'to')"
@
blur=
"changeWarningThresholdTo($index)"
>
<
template
v-if=
"!isEmptyOption"
#append
>
{{
ruleTypeOptions
[
props
.
rule_type
]?.
unit
||
""
}}
</
template
>
</el-input>
</el-form-item>
</div>
<div
v-else-if=
"header.prop == 'risk_level'"
>
<el-form-item
label=
""
:prop=
"`[${$index}].risk_level`"
:rules=
"state.tableRules.risk_level"
>
<el-select
style=
"flex: 1"
v-model=
"state.form.ruleRows[$index].risk_level"
placeholder=
"请选择"
>
<el-option
v-for=
"item in riskLevelOptions($index)"
:key=
"item.id"
:label=
"item.name"
:value=
"item.id"
>
</el-option>
</el-select>
</el-form-item>
</div>
</template>
</el-table-column>
<el-table-column
prop=
""
label=
"操作"
width=
"150px"
>
<
template
#default
="{
$
index
}"
>
<div
class=
"table-operation"
>
<el-button
link
type=
"primary"
@
click=
"createRule($index)"
:disabled=
"state.form.ruleRows.length >= riskLevels.length"
>
新增
</el-button>
<span
class=
"line"
></span>
<el-button
link
type=
"primary"
@
click=
"removeRule($index)"
:disabled=
"state.form.ruleRows.length == 1"
>
删除
</el-button>
</div>
</
template
>
</el-table-column>
</el-table>
</el-form>
</div>
</div>
</template>
<
script
setup
>
import
{
computed
,
nextTick
,
onBeforeMount
,
reactive
,
ref
}
from
"
vue
"
;
import
gapTitle
from
"
@/components/gap-title.vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
{
Empty
,
GetRuleTypeOptions
}
from
"
@/components/env.js
"
;
const
props
=
defineProps
({
form
:
{
type
:
Object
,
default
:
null
,
},
rule_type
:
{
type
:
String
,
default
:
"
1
"
,
},
});
const
ruleTypeOptions
=
ref
({});
const
getRuleTypeOptions
=
async
(
cb
)
=>
{
ruleTypeOptions
.
value
=
await
GetRuleTypeOptions
();
cb
&&
cb
();
};
const
validateFrom
=
(
rule
,
value
,
callback
,
index
)
=>
{
let
thisRow
=
state
.
form
.
ruleRows
[
index
];
// 如果只有一条数据,并且上限下限都没有填写,则提示错误
if
(
state
.
form
.
ruleRows
.
length
==
1
&&
thisRow
.
from
===
""
&&
thisRow
.
to
==
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
// 当前下限不是第一条数据,并且为空,提示错误
if
(
index
>
0
&&
value
===
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
callback
();
};
const
validateTo
=
(
rule
,
value
,
callback
,
index
)
=>
{
let
thisRow
=
state
.
form
.
ruleRows
[
index
];
// 如果只有一条数据,并且上限下限都没有填写,则提示错误
if
(
state
.
form
.
ruleRows
.
length
==
1
&&
thisRow
.
from
===
""
&&
thisRow
.
to
==
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
// 当前上限不是最后一条数据,并且为空,提示错误
if
(
index
<
state
.
form
.
ruleRows
.
length
-
1
&&
value
===
""
)
{
return
callback
(
new
Error
(
"
请输入
"
));
}
callback
();
};
const
state
=
reactive
({
form
:
{
ruleRows
:
[],
},
tableRules
:
{
from
:
(
index
)
=>
{
return
[
{
validator
:
(
rule
,
value
,
callback
)
=>
validateFrom
(
rule
,
value
,
callback
,
index
),
trigger
:
"
blur
"
,
},
];
},
to
:
(
index
)
=>
{
return
[
{
validator
:
(
rule
,
value
,
callback
)
=>
validateTo
(
rule
,
value
,
callback
,
index
),
trigger
:
"
blur
"
,
},
];
},
risk_level
:
[{
required
:
true
,
message
:
"
请选择
"
,
trigger
:
"
change
"
}],
},
});
const
form_ref
=
ref
(
null
);
const
Submit
=
async
()
=>
{
let
form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
form_ref
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
return
form_valid
;
};
const
riskLevels
=
ref
([
{
id
:
4
,
name
:
"
重大风险
"
,
},
{
id
:
3
,
name
:
"
较大风险
"
,
},
{
id
:
2
,
name
:
"
一般风险
"
,
},
{
id
:
1
,
name
:
"
低风险
"
,
},
]);
const
riskLevelOptions
=
computed
(()
=>
{
return
(
index
)
=>
{
let
risk_level
=
state
.
form
.
ruleRows
[
index
].
risk_level
;
let
rows
=
state
.
form
.
ruleRows
.
map
((
e
)
=>
e
.
risk_level
);
if
(
risk_level
)
{
let
i
=
rows
.
findIndex
((
e
)
=>
e
==
risk_level
);
rows
.
splice
(
i
,
1
);
}
return
riskLevels
.
value
.
filter
((
e
)
=>
!
rows
.
includes
(
e
.
id
));
};
});
const
ruleHeaders
=
[
{
prop
:
"
warning_threshold
"
,
label
:
"
预警阈值
"
,
width
:
"
500px
"
,
},
{
prop
:
"
risk_level
"
,
label
:
"
风险程度
"
,
},
];
const
createRule
=
(
index
=
-
1
)
=>
{
state
.
form
.
ruleRows
.
splice
(
index
+
1
,
0
,
{
from
:
""
,
to
:
""
,
risk_level
:
""
,
});
};
const
setLimits
=
(
index
)
=>
{
let
rows
=
[...
state
.
form
.
ruleRows
];
rows
.
splice
(
index
,
1
);
return
(
rows
.
map
((
e
)
=>
{
return
{
down
:
e
.
from
,
up
:
e
.
to
,
};
})
||
[]
);
};
const
isEmptyOption
=
computed
(()
=>
{
return
Empty
(
props
.
rule_type
,
ruleTypeOptions
.
value
);
});
const
limit
=
computed
(()
=>
{
return
(
ruleTypeOptions
.
value
[
props
.
rule_type
]
||
{
down
:
""
,
up
:
""
,
}
);
});
const
changeWarningThresholdFrom
=
(
index
)
=>
{
let
{
down
,
up
}
=
limit
.
value
;
let
{
from
,
to
}
=
state
.
form
.
ruleRows
[
index
];
if
(
to
!==
""
&&
from
!==
""
&&
from
>=
+
to
)
{
ElMessage
.
error
(
`下限不能大于上限`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
else
if
(
down
!==
""
&&
+
from
<
+
down
)
{
ElMessage
.
error
(
`下限不能小于
${
down
}
`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
else
if
(
up
!=
""
&&
+
from
>
+
up
)
{
ElMessage
.
error
(
`上限不能超过
${
up
}
`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
return
;
}
let
rows
=
setLimits
(
index
);
if
(
rows
.
length
==
0
)
return
;
let
items
=
rows
.
filter
((
e
,
i
)
=>
{
let
isPassDown
=
e
.
down
!==
""
?
+
e
.
down
<=
+
from
:
false
;
let
isLessUp
=
e
.
up
!==
""
?
+
e
.
up
>=
+
from
:
false
;
let
isLessDownAndPassUp
=
e
.
down
!==
""
&&
e
.
up
!==
""
&&
to
!==
""
?
+
from
<
+
e
.
down
&&
+
to
>
+
e
.
up
:
false
;
return
(
isPassDown
&&
isLessUp
)
||
isLessDownAndPassUp
;
});
if
(
items
.
length
>
0
)
{
ElMessage
.
error
(
`该范围已被设置`
);
state
.
form
.
ruleRows
[
index
].
from
=
""
;
}
};
const
inputNum
=
(
index
,
key
)
=>
{
if
(
state
.
form
.
ruleRows
[
index
][
key
]
==
""
)
return
;
if
(
state
.
form
.
ruleRows
[
index
][
key
]
==
"
-
"
)
return
;
state
.
form
.
ruleRows
[
index
][
key
]
=
`
${
state
.
form
.
ruleRows
[
index
][
key
]}
`
.
replace
(
/
[^\-
?
\d
.
]
/g
,
""
)
//只允许输入负号,数字,小数点
.
replace
(
/
(\-)
+/
,
"
$1
"
)
//过滤连续多个负号
.
replace
(
/
(\.)
+/
,
"
$1
"
)
//过滤连续多个小数点
.
replace
(
/
(\.\d
+
)\.
/g
,
"
$1
"
)
//过滤出现多个小数点
.
replace
(
/
(\d)\-
/g
,
"
$1
"
);
//过滤处于非开头的负号
};
const
changeWarningThresholdTo
=
(
index
)
=>
{
let
{
down
,
up
}
=
limit
.
value
;
let
{
from
,
to
}
=
state
.
form
.
ruleRows
[
index
];
if
(
to
!==
""
&&
from
!==
""
&&
from
>=
+
to
)
{
ElMessage
.
error
(
`下限不能大于上限`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
else
if
(
down
!==
""
&&
+
to
<
+
down
)
{
ElMessage
.
error
(
`下限不能小于
${
down
}
`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
else
if
(
up
!=
""
&&
+
to
>
+
up
)
{
ElMessage
.
error
(
`上限不能超过
${
up
}
`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
return
;
}
let
rows
=
setLimits
(
index
);
if
(
rows
.
length
==
0
)
return
;
let
items
=
rows
.
filter
((
e
,
i
)
=>
{
let
isPassDown
=
e
.
down
!==
""
?
+
e
.
down
<=
+
to
:
false
;
let
isLessUp
=
e
.
up
!==
""
?
+
e
.
up
>=
+
to
:
false
;
let
isLessDownAndPassUp
=
e
.
down
!==
""
&&
e
.
up
!==
""
&&
from
!==
""
?
+
from
<
+
e
.
down
&&
+
to
>
+
e
.
up
:
false
;
return
(
isPassDown
&&
isLessUp
)
||
isLessDownAndPassUp
;
});
if
(
items
.
length
>
0
)
{
ElMessage
.
error
(
`该范围已被设置`
);
state
.
form
.
ruleRows
[
index
].
to
=
""
;
}
};
const
removeRule
=
(
index
)
=>
{
state
.
form
.
ruleRows
.
splice
(
index
,
1
);
};
const
info
=
()
=>
{
if
(
!
props
.
form
||
props
.
form
?.
length
==
0
)
{
getRuleTypeOptions
();
createRule
();
return
;
}
getRuleTypeOptions
(()
=>
{
state
.
form
.
ruleRows
=
props
.
form
?.
map
((
e
)
=>
{
return
{
from
:
e
.
from
,
to
:
e
.
to
,
risk_level
:
e
.
risk_level
,
};
})
||
[];
if
(
state
.
form
.
ruleRows
.
length
==
0
)
{
createRule
();
}
});
};
onBeforeMount
(()
=>
{
info
();
});
defineExpose
({
Submit
,
form
:
state
.
form
,
form_ref
,
});
</
script
>
<
style
lang=
"scss"
scoped
>
.gateway-form
{
margin-bottom
:
16px
;
:deep
(
.gap-title
)
{
margin-bottom
:
16px
;
}
&
-item
{
max-width
:
1080px
;
width
:
100%
;
padding-left
:
120px
;
:deep
(
.el-table
thead
th
)
{
background-color
:
#f5f6f9
;
}
.indicator-expression
{
height
:
300px
;
width
:
100%
;
:deep
(
.vue-ace-editor
)
{
margin-top
:
0
;
}
}
}
}
:deep
(
.el-form-item
)
{
margin-bottom
:
0
!
important
;
}
.warning-threshold
{
display
:
flex
;
align-items
:
center
;
:deep
(
.el-input__wrapper
)
{
border-top-right-radius
:
0
;
border-bottom-right-radius
:
0
;
}
:deep
(
.el-input-group__append
,
.el-input-group__prepend
)
{
border-radius
:
4px
;
border-top-left-radius
:
0
;
border-bottom-left-radius
:
0
;
}
}
.to
{
margin
:
0
16px
;
}
.line
{
width
:
1px
;
height
:
14px
;
background-color
:
#c1c7d7
;
margin
:
0
16px
;
display
:
inline-block
;
}
.rule-table
{
:deep
(
.el-table
thead
th
)
{
background-color
:
#f5f6f9
;
}
}
</
style
>
src/page/main/forewarning/rule-set/modules/interface.js
deleted
100644 → 0
View file @
dd5821ad
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
const
setParams
=
(
res
,
{
id
})
=>
{
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
.
type_com_ref
.
alert_rule_type
,
}
}
}
let
alert_condition
=
[]
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
=>
{
let
obj
=
{
risk_level
:
+
e
.
risk_level
}
if
(
e
.
to
!==
""
)
{
obj
.
thresholds_max
=
+
e
.
to
}
if
(
e
.
from
!==
""
)
{
obj
.
thresholds_min
=
+
e
.
from
}
return
obj
})
}
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
);
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
src/page/main/forewarning/rule-set/modules/static.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"static-form"
>
<el-form
:model=
"state.form"
ref=
"form_ref"
:rules=
"state.rules"
label-width=
"120px"
>
<div
class=
"static-form-item"
>
<el-form-item
label=
"预警对象/分类"
prop=
"warn_type"
>
<el-cascader
:disabled=
"props.isEdit"
ref=
"cascader_ref"
style=
"flex: 1"
placeholder=
"请选择预警对象/分类"
:options=
"staticTypeOptions"
v-model=
"state.form.warn_type"
@
change=
"changeWarnStaticType"
:props=
"cascaderProps"
>
</el-cascader>
</el-form-item>
<el-form-item
label=
"预警指标"
prop=
"warn_indicator"
>
<el-select
style=
"flex: 1"
:disabled=
"!formFormat.warn_type || props.isEdit"
v-model=
"state.form.warn_indicator"
placeholder=
"请选择预警指标"
@
change=
"chooseWarnIndicator"
>
<el-option
v-for=
"item in warningIndexOptions"
:key=
"item.id"
:label=
"item.metric_name"
:value=
"item.id"
>
</el-option>
</el-select>
</el-form-item>
</div>
<div>
<div
v-if=
"state.form.warning_scpoe_form.length > 0"
>
<gap-title
:hasLine=
"true"
title=
"预警范围"
></gap-title>
<div
class=
"static-form-item"
>
<div
class=
"warning-scope-main"
>
<div
class=
"warn-scpoe-form"
v-for=
"(item, index) in state.form.warning_scpoe_form"
:key=
"index"
>
<el-form-item
:label=
"item.chinese_name"
>
<el-select
class=
"warn-scpoe-select"
v-model=
"item.select"
style=
"width: 114px"
>
<el-option
v-for=
"(value, key) in selectRule"
:key=
"key"
:label=
"value"
:value=
"key"
/>
</el-select>
</el-form-item>
<el-form-item
label=
""
class=
"no-el-label warn-scpoe-input-item"
prop=
"value"
:rules=
"[
{
validator: (rule, value, callback) => validateValue(rule, value, callback, item, index),
trigger: showSelect.includes(item.select) ? 'change' : 'blur',
},
]">
<el-input
class=
"warn-scpoe-input-value"
v-model=
"state.form.warning_scpoe_form[index].value"
:placeholder=
"`请输入$
{item.chinese_name}`"
v-if="!item.is_linked"
:disabled="item.select == 'all'">
</el-input>
<el-select
class=
"warn-scpoe-input-value"
v-else
v-model=
"item.value"
:placeholder=
"`请选择$
{item.chinese_name}`"
filterable
:loading="item.loading"
remote
:disabled="item.select == 'all'"
:remote-method="(query) => remoteMethod(query, index, item)">
<el-option
v-for=
"item in item.options"
:key=
"item"
:label=
"item"
:value=
"item"
>
</el-option>
</el-select>
</el-form-item>
</div>
</div>
</div>
</div>
<gap-title
:hasLine=
"true"
title=
"预警规则"
></gap-title>
<div
class=
"static-form-item"
>
<div
class=
"warning-rule-main"
>
<el-form-item
label=
"风险程度"
prop=
"risk_level"
v-if=
"isEmpty"
>
<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>
<Gateway
v-else
ref=
"warn_type_com"
:form=
"rule_rows"
:rule_type=
"alert_rule_type"
/>
</div>
</div>
</div>
</el-form>
</div>
</
template
>
<
script
setup
>
import
{
computed
,
nextTick
,
onMounted
,
reactive
,
ref
,
shallowReactive
,
watch
}
from
"
vue
"
;
import
gapTitle
from
"
@/components/gap-title.vue
"
;
import
Gateway
from
"
./gateway.vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
{
GetRuleTypeOptions
,
Empty
}
from
"
@/components/env.js
"
;
const
showSelect
=
[
"
=~
"
,
"
!~
"
];
const
selectRule
=
ref
({
all
:
"
全部
"
,
"
=
"
:
"
等于
"
,
"
!=
"
:
"
不等于
"
,
"
=~
"
:
"
正则匹配
"
,
"
!~
"
:
"
正则不匹配
"
,
});
const
riskLevelOptions
=
ref
([
{
id
:
4
,
name
:
"
重大风险
"
,
},
{
id
:
3
,
name
:
"
较大风险
"
,
},
{
id
:
2
,
name
:
"
一般风险
"
,
},
{
id
:
1
,
name
:
"
低风险
"
,
},
]);
const
props
=
defineProps
({
form
:
{
type
:
Object
,
default
:
null
,
},
isEdit
:
{
type
:
Boolean
,
default
:
false
,
},
});
const
validateValue
=
(
rule
,
value
,
callback
,
item
,
index
)
=>
{
if
(
!
item
.
is_required
||
item
.
select
==
"
all
"
)
return
callback
();
if
(
item
.
value
==
""
)
{
let
msg
=
showSelect
.
includes
(
item
.
select
)
?
`请选择
${
item
.
chinese_name
}
`
:
`请输入
${
item
.
chinese_name
}
`
;
return
callback
(
new
Error
(
msg
));
}
return
callback
();
};
const
state
=
reactive
({
form
:
{
warn_type
:
[],
warn_indicator
:
""
,
risk_level
:
""
,
warning_scpoe_form
:
[],
},
rules
:
{
warn_type
:
[{
type
:
"
array
"
,
required
:
true
,
message
:
"
请选择预警对象/分类
"
,
trigger
:
"
change
"
}],
warn_indicator
:
[{
required
:
true
,
message
:
"
请选择预警指标
"
,
trigger
:
"
change
"
}],
risk_level
:
[{
required
:
true
,
message
:
"
请选择风险程度
"
,
trigger
:
"
change
"
}],
},
});
const
info
=
()
=>
{
state
.
form
.
warn_type
=
props
.
form
.
warn_target
&&
props
.
form
.
warn_type
?
[
props
.
form
.
warn_target
,
props
.
form
.
warn_type
]
:
[];
state
.
form
.
warn_indicator
=
props
.
form
.
warn_indicator
;
alert_rule_type
.
value
=
props
.
form
.
rule_type
||
"
1
"
;
let
params
=
{
page
:
1
,
page_size
:
10000000000000
,
class_id
:
props
.
form
.
warn_type
,
is_enabled
:
1
,
};
getWarningIndicator
(
params
,
()
=>
{
state
.
form
.
warning_scpoe_form
=
props
.
form
?.
warning_scpoe_form
||
[];
});
state
.
form
.
risk_level
=
props
.
form
.
risk_level
;
};
const
ruleTypeOptions
=
ref
({});
const
getRuleTypeOptions
=
async
(
cb
)
=>
{
ruleTypeOptions
.
value
=
await
GetRuleTypeOptions
();
if
(
props
.
form
)
{
info
();
}
};
watch
(
()
=>
props
.
form
,
(
n
)
=>
{
if
(
!
n
)
return
;
info
();
},
{
deep
:
true
,
}
);
const
module_data
=
ref
({});
const
alert_rule_type
=
ref
(
""
);
const
isEmpty
=
computed
(()
=>
{
return
Empty
(
alert_rule_type
.
value
,
ruleTypeOptions
.
value
);
});
const
emits
=
defineEmits
([
"
update-duration
"
]);
const
chooseWarnIndicator
=
()
=>
{
axios
.
get
(
"
/v1/api/metric_config
"
,
{
params
:
{
id
:
state
.
form
.
warn_indicator
,
},
})
.
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
module_data
.
value
=
res
.
data
.
data
;
alert_rule_type
.
value
=
module_data
.
value
.
alert_rule_type
;
state
.
form
.
warning_scpoe_form
=
module_data
.
value
.
alert_range
.
map
((
e
)
=>
{
return
{
...
e
,
value
:
""
,
select
:
"
all
"
,
options
:
[],
loading
:
false
,
};
});
emits
(
"
update-duration
"
,
module_data
.
value
);
}
else
{
ElMessage
.
error
(
res
.
data
.
data
);
}
});
};
const
remoteMethod
=
(
query
,
index
,
item
)
=>
{
state
.
form
.
warning_scpoe_form
[
index
].
loading
=
true
;
const
params
=
{
metric_name
:
item
.
metric_name
,
// metric_name: "grpc_client_handled_total",
metric_label
:
item
.
metric_label
,
// metric_label: "grpc_method",
value
:
query
,
};
axios
.
get
(
`/v1/api/prometheus/value`
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
state
.
form
.
warning_scpoe_form
[
index
].
options
=
res
.
data
.
data
.
list
||
[];
state
.
form
.
warning_scpoe_form
[
index
].
loading
=
false
;
}
});
};
const
warn_type_com_form
=
computed
(()
=>
props
.
form
?.
warn_type_com
||
null
);
const
cascaderProps
=
{
value
:
"
class_id
"
,
label
:
"
class_name
"
,
};
const
staticTypeOptions
=
ref
([]);
const
staticTypeFormat
=
(
res
)
=>
{
let
arr
=
res
?.
map
((
e
)
=>
{
let
children
=
[];
let
is_disabled
=
false
;
if
(
e
.
children
?.
length
==
0
&&
e
.
parent_id
==
0
)
{
children
=
[];
is_disabled
=
true
;
}
else
{
children
=
staticTypeFormat
(
e
.
children
);
is_disabled
=
false
;
}
return
{
...
e
,
children
:
children
,
disabled
:
is_disabled
,
};
});
return
arr
;
};
const
getStaticTypeOptions
=
()
=>
{
axios
.
get
(
"
/v1/api/alert_class/tree
"
).
then
(
async
(
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
staticTypeOptions
.
value
=
staticTypeFormat
(
res
.
data
.
data
);
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
const
formFormat
=
computed
(()
=>
{
let
[
warn_target
=
""
,
warn_type
=
""
]
=
state
.
form
.
warn_type
||
[];
let
obj
=
{
...
state
.
form
,
warn_target
,
warn_type
,
isEmpty
:
isEmpty
.
value
,
alert_rule_type
:
module_data
.
value
.
alert_rule_type
,
};
if
(
!
isEmpty
.
value
)
{
obj
=
{
...
obj
,
...(
warn_type_com
.
value
?.
form
||
{}),
};
}
return
obj
;
});
const
warningIndexOptions
=
ref
({});
const
cascader_ref
=
ref
(
null
);
const
changeWarnStaticType
=
async
()
=>
{
let
class_id
=
state
.
form
.
warn_type
[
1
];
if
(
!
class_id
)
return
;
let
params
=
{
page
:
1
,
page_size
:
10000000000000
,
class_id
,
is_enabled
:
1
};
getWarningIndicator
(
params
);
};
const
getWarningIndicator
=
(
params
,
cb
)
=>
{
axios
.
get
(
"
/v1/api/metric_config/list
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
warningIndexOptions
.
value
=
res
.
data
.
data
?.
list
||
[];
if
(
!
cb
)
{
state
.
form
.
warn_indicator
=
warningIndexOptions
.
value
[
0
]?.
id
||
""
;
if
(
state
.
form
.
warn_indicator
)
{
chooseWarnIndicator
();
}
}
else
{
cb
();
}
setTimeout
(()
=>
{
form_ref
.
value
.
clearValidate
([
"
warn_indicator
"
]);
});
}
});
};
const
changeRuleType
=
()
=>
{};
const
form_ref
=
ref
(
null
);
const
warn_type_com
=
ref
(
null
);
const
Submit
=
async
()
=>
{
let
form_valid
=
await
new
Promise
((
resolve
,
reject
)
=>
{
form_ref
.
value
.
validate
((
res
)
=>
resolve
(
res
));
});
if
(
isEmpty
.
value
)
return
form_valid
;
let
warn_type_com_valid
=
await
warn_type_com
.
value
?.
Submit
();
return
form_valid
&&
warn_type_com_valid
;
};
const
ruleHeaders
=
[
{
prop
:
"
warning_threshold
"
,
label
:
"
预警阈值
"
,
width
:
"
500px
"
,
},
{
prop
:
"
risk_level
"
,
label
:
"
风险程度
"
,
},
];
const
rule_rows
=
computed
(()
=>
props
.
form
?.
ruleRows
||
[]);
onMounted
(()
=>
{
getStaticTypeOptions
();
getRuleTypeOptions
();
});
defineExpose
({
Submit
,
form
:
formFormat
,
form_ref
,
});
</
script
>
<
style
lang=
"scss"
scoped
>
.static-form
{
:deep
(
.gap-title
)
{
margin-bottom
:
16px
;
}
&
-item
{
max-width
:
1080px
;
width
:
100%
;
padding-left
:
8px
;
.warning-scope-main
{
// display: grid;
// grid-template-columns: 1fr 1fr;
// grid-column-gap: 16px;
:deep
(
.el-input-group__prepend
)
{
border-radius
:
4px
;
border-top-right-radius
:
0
;
border-bottom-right-radius
:
0
;
}
.warn-scpoe-form
{
width
:
100%
;
display
:
flex
;
align-items
:
center
;
.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
{
flex
:
1
;
.warn-scpoe-input-value
{
flex
:
1
;
:deep
(
.el-input__wrapper
)
{
border-top-left-radius
:
0
;
border-bottom-left-radius
:
0
;
}
}
}
}
}
}
}
.no-el-label
{
:deep
(
.el-form-item__content
)
{
margin-left
:
0
!
important
;
}
}
</
style
>
src/page/main/ticket/my-warn-ticket/detail/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
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"
v-if=
"valueData.status"
>
<span
class=
"status"
:class=
"`status-$
{valueData.status}`">
</span>
<span>
{{
statusOptions
[
valueData
[
item
.
prop
]]
}}
</span>
</span>
<span
v-else
>
-
</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/work_order/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
>
src/page/main/ticket/my-warn-ticket/index.vue
deleted
100644 → 0
View file @
dd5821ad
<
template
>
<div
class=
"my-warn-ticket"
>
<div
class=
"breadcrumb"
>
<bg-breadcrumb
/>
</div>
<div
class=
"content"
>
<bg-filter-group
@
search=
"changeSearch"
v-model=
"filter.keyword"
placeholder=
"请输入预警点/分类/指标"
>
<template
v-slot:filter_group
>
<div
class=
"left-filter filter_list"
>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
风险等级
</span>
<el-select
v-model=
"filter.risk_level"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(value, key, index) in riskLevels"
:key=
"'riskLevels' + index"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
状态
</span>
<el-select
v-model=
"filter.status"
placeholder=
"请选择"
style=
"width: 300px"
>
<el-option
v-for=
"(value, key, index) in statusOptions"
:key=
"'stateOptions' + index"
:label=
"value"
:value=
"key"
>
</el-option>
</el-select>
</div>
<div
class=
"filter_item"
>
<span
class=
"filter_title"
>
预警时段
</span>
<el-date-picker
v-model=
"filter.time"
style=
"width: 400px"
type=
"datetimerange"
value-format=
"YYYY-MM-DD HH:mm:ss"
range-separator=
"-"
start-placeholder=
"开始时间"
end-placeholder=
"结束时间"
>
</el-date-picker>
</div>
</div>
<div
class=
"right-action apaas_button"
>
<el-button
type=
"primary"
@
click=
"filterAction"
>
查询
</el-button>
<el-button
type=
"default"
@
click=
"filterClear"
>
重置
</el-button>
</div>
</
template
>
</bg-filter-group>
<div
class=
"table_container"
>
<div
class=
"table"
>
<bg-table
ref=
"listtable"
:headers=
"headers"
:rows=
"rows"
height=
"100%"
:isIndex=
"true"
:stripe=
"true"
>
<
template
v-slot:alert_point=
"{ row }"
>
<span
class=
"can_click_text"
@
click=
"goDetail(row)"
>
{{
row
.
alert_point
}}
</span>
</
template
>
<
template
v-slot:risk_level=
"{ row }"
>
{{
riskLevels
[
row
.
risk_level
]
}}
</
template
>
<
template
v-slot:current_value=
"{ row }"
>
{{
row
.
current_value
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
</
template
>
<
template
v-slot:warn_threshold=
"{ row }"
>
{{
row
.
alert_condition
.
thresholds_min
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
-
{{
row
.
alert_condition
.
thresholds_max
}}{{
ruleTypeOptions
[
row
.
alert_rule_type
]?.
unit
||
""
}}
</
template
>
<
template
v-slot:alert_time=
"{ row }"
>
{{
dateStringToDate
(
row
.
alert_time
)
}}
</
template
>
<
template
v-slot:last_push_time=
"{ row }"
>
{{
dateStringToDate
(
row
.
last_push_time
)
}}
</
template
>
<
template
#status
="{
row
}"
>
<span
:class=
"`circle status-$
{row.status}`">
</span>
{{
statusOptions
[
row
.
status
]
}}
</
template
>
<
template
#operation
="{
row
}"
>
<el-button
type=
"primary"
:disabled=
"row.status != 2 || row.is_disposed == 1"
link
size=
"small"
@
click=
"operation(row)"
>
处置反馈
</el-button>
</
template
>
</bg-table>
<div
class=
"pagination_box"
>
<bg-pagination
:page=
"filter.page"
:size=
"filter.page_size"
:total=
"tableTotal"
@
change-page=
"changePage"
@
change-size=
"changeSize"
>
</bg-pagination>
</div>
</div>
</div>
</div>
<FeedBack
v-model:visible=
"visible"
:active_row=
"active_row"
:isWarn=
"true"
/>
</div>
</template>
<
script
setup
>
import
{
reactive
,
ref
,
onBeforeMount
,
toRefs
,
computed
,
watch
,
nextTick
,
watchEffect
}
from
"
vue
"
;
import
{
ElMessage
}
from
"
element-plus
"
;
import
axios
from
"
@/request/http.js
"
;
import
bgBreadcrumb
from
"
@/components/bg-breadcrumb.vue
"
;
import
FeedBack
from
"
../modules/feedback.vue
"
;
import
{
useRouter
}
from
"
vue-router
"
;
import
{
GetRuleTypeOptions
,
dateStringToDate
}
from
"
@/components/env.js
"
;
const
router
=
useRouter
();
const
filter
=
reactive
({
risk_level
:
""
,
// 风险等级
status
:
""
,
// 状态
time
:
[],
keyword
:
""
,
page
:
1
,
page_size
:
10
,
});
const
tableTotal
=
ref
(
0
);
const
ruleTypeOptions
=
ref
({});
const
filterClear
=
()
=>
{
filter
.
warning_index
=
""
;
filter
.
risk_level
=
""
;
filter
.
status
=
""
;
filter
.
time
=
[];
filter
.
page_size
=
10
;
filter
.
page
=
1
;
changePage
(
1
);
};
// 重置筛选项
const
statusOptions
=
[
"
全部
"
,
"
已恢复
"
,
"
未恢复
"
,
"
已关闭
"
];
// const disposedOptions = ["", "已处置", "已处置"];
const
riskLevels
=
{
""
:
"
全部
"
,
1
:
"
低风险
"
,
2
:
"
一般风险
"
,
3
:
"
较大风险
"
,
4
:
"
重大风险
"
,
};
let
headers
=
reactive
([
{
label
:
"
预警点
"
,
prop
:
"
alert_point
"
,
align
:
"
left
"
,
width
:
180
,
},
{
label
:
"
预警时间
"
,
prop
:
"
alert_time
"
,
align
:
"
left
"
,
width
:
160
,
},
{
label
:
"
预警分类
"
,
prop
:
"
class_parent_name
"
,
align
:
"
left
"
,
},
{
label
:
"
预警指标
"
,
prop
:
"
class_name
"
,
align
:
"
left
"
,
},
{
label
:
"
风险等级
"
,
prop
:
"
risk_level
"
,
align
:
"
left
"
,
},
{
label
:
"
当前报警值
"
,
prop
:
"
current_value
"
,
align
:
"
left
"
,
},
{
label
:
"
预警阀值
"
,
prop
:
"
warn_threshold
"
,
align
:
"
left
"
,
},
{
label
:
"
推送次数
"
,
prop
:
"
push_count
"
,
align
:
"
left
"
,
},
{
label
:
"
最近推送时间
"
,
prop
:
"
last_push_time
"
,
align
:
"
left
"
,
width
:
160
,
},
{
label
:
"
状态
"
,
prop
:
"
status
"
,
align
:
"
left
"
,
width
:
90
,
},
{
label
:
"
操作
"
,
prop
:
"
operation
"
,
align
:
"
left
"
,
width
:
80
,
fixed
:
"
right
"
,
},
]);
let
rows
=
ref
([]);
const
changeSize
=
(
size
)
=>
{
filter
.
page_size
=
size
;
changePage
(
1
);
};
const
changePage
=
(
page
)
=>
{
filter
.
page
=
page
;
getTableRows
();
};
const
changeSearch
=
(
val
)
=>
{
filter
.
keyword
=
val
;
changePage
(
1
);
};
// 表格关键字筛选
const
filterAction
=
()
=>
{
changePage
(
1
);
};
// 查询按钮
const
getTableRows
=
async
()
=>
{
let
[
start_time
=
""
,
end_time
=
""
]
=
filter
.
time
||
[];
let
params
=
{
...
filter
,
start_time
,
end_time
,
};
Reflect
.
deleteProperty
(
params
,
"
time
"
);
axios
.
get
(
"
/v1/api/work_order/alert/list
"
,
{
params
}).
then
((
res
)
=>
{
if
(
res
.
data
.
code
==
200
)
{
let
{
list
,
total_count
}
=
res
.
data
.
data
;
rows
.
value
=
list
||
[];
tableTotal
.
value
=
total_count
;
}
else
{
ElMessage
.
error
(
res
.
data
.
msg
);
}
});
};
// 处置反馈
const
visible
=
ref
(
false
);
const
active_row
=
ref
(
null
);
const
operation
=
(
row
)
=>
{
active_row
.
value
=
{
...
row
,
url
:
"
/v1/api/work_order/alert/dispose
"
};
visible
.
value
=
true
;
};
const
goDetail
=
({
id
})
=>
{
router
.
push
({
path
:
"
/ticket/my-warn-ticket/detail
"
,
query
:
{
id
,
},
});
};
const
getRuleTypeOptions
=
async
()
=>
{
ruleTypeOptions
.
value
=
await
GetRuleTypeOptions
();
getTableRows
();
};
onBeforeMount
(()
=>
{
getRuleTypeOptions
();
});
</
script
>
<
style
lang=
"scss"
scoped
>
.my-warn-ticket
{
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
;
display
:
flex
;
flex-direction
:
column
;
padding
:
16px
;
:deep
(
.bg-filter-group
)
{
padding
:
0
;
}
.filter-group
{
.left-filter
{
display
:
flex
;
justify-content
:
start
;
flex-wrap
:
wrap
;
}
.right-action
{
white-space
:
nowrap
;
}
}
.table_container
{
flex
:
1
;
display
:
flex
;
flex-direction
:
column
;
position
:
relative
;
.table
{
position
:
absolute
;
flex
:
1
;
width
:
100%
;
height
:
calc
(
100%
-
48px
);
.href
{
font-size
:
14px
;
color
:
#3759be
;
cursor
:
pointer
;
}
}
}
:deep
(
.el-button.is-link
)
{
line-height
:
1
;
}
.bg-pagination
{
bottom
:
unset
;
}
}
}
</
style
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment