feat: 告警记录页面

This commit is contained in:
leiqiaochu 2023-02-28 21:49:28 +08:00
parent b92fe00806
commit 962fa72fdb
7 changed files with 325 additions and 182 deletions

View File

@ -18,4 +18,9 @@ export const getOrgList = (parmas?:any) => server.get('/organization/_query/no-p
/**
*
*/
export const query = (data:any) => server.post('/alarm/record/_query/',data);
export const query = (data:any) => server.post('/alarm/record/_query/',data);
/**
*
*/
export const handleLog = (data:any) => server.post('/alarm/record/_handle',data)

View File

@ -60,6 +60,8 @@ const iconKeys = [
'RedoOutlined',
'VideoCameraOutlined',
'HistoryOutlined',
'ToolOutlined',
'FileOutlined',
]
const Icon = (props: {type: string}) => {

View File

@ -9,6 +9,7 @@
<JTable
:columns="columns"
:request="queryList"
:gridColumn="3"
ref="tableRef"
:defaultParams="{
sorts: [{ name: 'createTime', order: 'desc' }],
@ -42,7 +43,7 @@
</slot>
</template>
<template #content>
<Ellipsis>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 600; font-size: 16px">
{{ slotProps.name }}
</span>
@ -70,48 +71,25 @@
</a-row>
</template>
<template #actions="item">
<a-tooltip
v-bind="item.tooltip"
:title="item.disabled && item.tooltip.title"
<PermissionButton
v-if="
item.key != 'trigger' ||
slotProps.sceneTriggerType == 'manual'
"
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{ ...item.tootip }"
@click="item.onClick"
>
<a-popconfirm
v-if="item.popConfirm"
v-bind="item.popConfirm"
:disabled="item.disabled"
okText="确定"
cancelText="取消"
>
<a-button :disabled="item.disabled">
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-button>
</a-popconfirm>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<a-button
:disabled="item.disabled"
@click="item.onClick"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-button>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-tooltip>
</PermissionButton>
</template>
</CardBox>
</template>
@ -151,45 +129,29 @@
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip
v-for="i in getActions(slotProps)"
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
v-bind="i.tooltip"
>
<span
<PermissionButton
v-if="
i.key != 'trigger' ||
slotProps.sceneTriggerType == 'manual'
"
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
style="padding: 0px"
>
<a-popconfirm
v-if="i.popConfirm"
v-bind="i.popConfirm"
okText="确定"
cancelText="取消"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-popconfirm>
<a-button
style="padding: 0"
type="link"
v-else
@click="i.onClick && i.onClick(slotProps)"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-button>
</span>
</a-tooltip>
<template #icon
><AIcon :type="i.icon"
/></template>
</PermissionButton>
</template>
</a-space>
</template>
</JTable>
@ -214,7 +176,6 @@ import { message } from 'ant-design-vue';
import { getImage } from '@/utils/comm';
import { useMenuStore } from '@/store/menu';
import encodeQuery from '@/utils/encodeQuery';
import { useStorage } from '@vueuse/core';
const params = ref<Record<string, any>>({});
let isAdd = ref<number>(0);
let title = ref<string>('');
@ -290,8 +251,11 @@ const columns = [
sorts: { createTime: 'desc' },
}),
);
if(res.status === 200){
return res.result.map((item:any) => ({label:item.name, value:item.id}))
if (res.status === 200) {
return res.result.map((item: any) => ({
label: item.name,
value: item.id,
}));
}
return [];
},
@ -303,26 +267,26 @@ const columns = [
key: 'state',
scopedSlots: true,
search: {
type: 'select',
options: [
{
label: '正常',
value: 'enabled',
},
{
label: '禁用',
value: 'disabled',
},
],
},
type: 'select',
options: [
{
label: '正常',
value: 'enabled',
},
{
label: '禁用',
value: 'disabled',
},
],
},
},
{
title: '说明',
dataIndex: 'description',
key: 'description',
search:{
type:'string',
}
search: {
type: 'string',
},
},
{
title: '操作',
@ -396,7 +360,11 @@ const getActions = (
icon: 'EditOutlined',
onClick: () => {
menuStory.jumpPage('rule-engine/Alarm/Configuration/Save',{},{id:data.id});
menuStory.jumpPage(
'rule-engine/Alarm/Configuration/Save',
{},
{ id: data.id },
);
},
},
{
@ -456,8 +424,6 @@ const getActions = (
icon: 'DeleteOutlined',
},
];
if (type === 'card')
return actions.filter((i: ActionsType) => i.key !== 'view');
return actions;
};
const add = () => {

View File

@ -0,0 +1,38 @@
<template>
<page-container>
<Search :columns="columns" target="alarm-log-detail"></Search>
<JTable :columns="columns" model="TABLE" :request="queryList"></JTable>
</page-container>
</template>
<script lang="ts" setup>
const columns = [{
title:'告警时间',
dataIndex:'alarmTime',
key:'alarmTime',
search:{
type:'date'
}
},{
title:'告警名称',
dataIndex:'alarmConfigName',
key:'alarmConfigName',
},{
title:'说明',
dataIndex:'description',
key:'description'
},{
title:'操作',
dataIndex:'action',
key:'action'
}]
/**
* 获取详情列表
*/
const queryList = () =>{
}
</script>
<style lang="less" scoped>
</style>

View File

@ -0,0 +1,79 @@
<template>
<a-modal
title="告警处理"
okText="确定"
cancelText="取消"
visible
@cancel="handleCancel"
@ok="handleSave"
destroyOnClose
:confirmLoading="loading"
>
<a-form :rules="rules" layout="vertical" ref="formRef" :model="form">
<a-form-item label="处理结果" name="describe">
<a-textarea
:rows="8"
:maxlength="200"
showCount
placeholder="请输入处理结果"
v-model:value="form.describe"
></a-textarea>
</a-form-item>
</a-form>
</a-modal>
</template>
<script lang="ts" setup>
import { handleLog } from '@/api/rule-engine/log';
import { onlyMessage } from '@/utils/comm';
const props = defineProps({
data: {
type: Object,
},
});
const loading = ref<boolean>(false);
const formRef = ref();
const rules = {
describe: [
{
required: true,
message: '请输入处理结果',
},
],
};
const form = reactive({
describe: '',
});
let visible = ref(true);
const emit = defineEmits(['closeSolve'])
const handleCancel = () => {
emit('closeSolve');
};
const handleSave = () => {
loading.value = true;
formRef.value
.validate()
.then(async () => {
const res = await handleLog({
describe: form.describe,
type: 'user',
state: 'normal',
alarmRecordId: props.data?.current?.id || '',
alarmConfigId: props.data?.current?.alarmConfigId || '',
alarmTime: props?.data?.current?.alarmTime || '',
});
if (res.status === 200) {
onlyMessage('操作成功!');
} else {
onlyMessage('操作失败!', 'error');
}
loading.value = false;
})
.catch((error) => {
console.log(error);
loading.value = false;
});
};
</script>
<style lang="less" scoped>
</style>

View File

@ -24,11 +24,18 @@
v-if="props.type === 'org'"
@search="search"
></Search>
<JTable :columns="columns" :request="handleSearch" :params="params">
<JTable
:columns="columns"
:request="handleSearch"
:params="params"
:gridColumn="2"
model="CARD"
>
<template #card="slotProps">
<CardBox
:value="slotProps"
v-bind="slotProps"
:actions="getActions(slotProps, 'card')"
:statusText="
data.defaultLevel.find(
(i) => i.level === slotProps.level,
@ -39,7 +46,7 @@
<img :src="imgMap.get(slotProps.targetType)" alt="" />
</template>
<template #content>
<Ellipsis>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 500">
{{ slotProps.alarmName }}
</span>
@ -90,10 +97,25 @@
</span>
</a-col>
</a-row>
</template>
<template #actions="item">
<PermissionButton
:disabled="item.key === 'solve' && slotProps.state.value ==='normal'"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</PermissionButton>
</template>
</CardBox>
</template>
</JTable>
<SolveLog :data="data" v-if="data.solveVisible" @closeSolve="closeSolve"/>
</div>
</template>
@ -111,6 +133,11 @@ import { useAlarmStore } from '@/store/alarm';
import { storeToRefs } from 'pinia';
import { Store } from 'jetlinks-store';
import moment from 'moment';
import type { ActionsType } from '@/components/Table';
import SolveLog from '../SolveLog/index.vue'
import { useMenuStore } from '@/store/menu';
const menuStory = useMenuStore();
const alarmStore = useAlarmStore();
const { data } = storeToRefs(alarmStore);
const getDefaulitLevel = () => {
@ -156,11 +183,11 @@ const columns = [
},
},
{
title: '最近告警事件',
title: '最近告警时间',
dataIndex: 'alarmTime',
key: 'alarmTime',
search: {
type: 'dateTime',
type: 'date',
},
},
{
@ -254,12 +281,7 @@ let param = reactive({
pageSize: 10,
terms: [],
});
// let dataSource = reactive({
// data: [],
// pageSize: 10,
// pageIndex: 0,
// total: 0,
// });
const handleSearch = async (params: any) => {
const resp = await query(params);
if (resp.status === 200) {
@ -284,33 +306,97 @@ const handleSearch = async (params: any) => {
};
watchEffect(() => {
if (props.type !== 'all' && !props.id) {
params.value.terms.push({
termType: 'eq',
column: 'targetType',
value: props.type,
type: 'and',
});
params.value.terms = [
{
termType: 'eq',
column: 'targetType',
value: props.type,
type: 'and',
},
];
}
if (props.id) {
params.value.terms.push({
termType: 'eq',
column: 'alarmConfigId',
value: props.id,
type: 'and',
});
params.value.terms = [
{
termType: 'eq',
column: 'alarmConfigId',
value: props.id,
type: 'and',
},
];
}
if(props.type === 'all'){
params.value.terms = [];
}
});
const search = (data: any) => {
const dt = {
pageSize: 10,
terms: [...data?.terms],
};
params.value.terms = [...data?.terms];
if (props.type !== 'all' && !props.id) {
params.value.terms.push(
{
termType: 'eq',
column: 'targetType',
value: props.type,
type: 'and',
},
);
}
if (props.id) {
params.value.terms.push (
{
termType: 'eq',
column: 'alarmConfigId',
value: props.id,
type: 'and',
},
);
}
};
const log = () => {
console.log(data.value.defaultLevel);
const getActions = (
currentData: Partial<Record<string, any>>,
type: 'card',
): ActionsType[] => {
if (!currentData) return [];
const actions = [
{
key: 'solve',
text: '告警处理',
tooltip: {
title: '告警处理',
},
icon: 'ToolOutlined',
onClick: () =>{
data.value.current = currentData;
data.value.solveVisible = true;
}
},
{
key: 'log',
text: '告警日志',
tooltip: {
title: '告警日志',
},
icon: 'FileOutlined',
onClick: () =>{
menuStory.jumpPage(`rule-engine/Alarm/Log/Detail`,{id:currentData.id});
}
},
{
key: 'detail',
text: '处理记录',
tooltip: {
title: '处理记录',
},
icon: 'FileTextOutlined',
},
];
return actions;
};
log();
const closeSolve = () =>{
data.value.solveVisible = false
}
</script>
<style lang="less" scoped>
</style>

View File

@ -40,7 +40,7 @@
</slot>
</template>
<template #content>
<Ellipsis>
<Ellipsis style="width: calc(100% - 100px)">
<span style="font-weight: 600; font-size: 16px">
{{ slotProps.name }}
</span>
@ -56,44 +56,23 @@
</a-row>
</template>
<template #actions="item">
<a-tooltip
v-bind="item.tooltip"
:title="item.disabled && item.tooltip.title"
<PermissionButton
:disabled="item.disabled"
:popConfirm="item.popConfirm"
:tooltip="{
...item.tooltip,
}"
@click="item.onClick"
>
<a-popconfirm
v-if="item.popConfirm"
v-bind="item.popConfirm"
:disabled="item.disabled"
okText="确定"
cancelText="取消"
>
<a-button :disabled="item.disabled">
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-button>
</a-popconfirm>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<a-button
:disabled="item.disabled"
@click="item.onClick"
>
<AIcon
type="DeleteOutlined"
v-if="item.key === 'delete'"
/>
<template v-else>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-button>
<AIcon :type="item.icon" />
<span>{{ item?.text }}</span>
</template>
</a-tooltip>
</PermissionButton>
</template>
</CardBox>
</template>
@ -113,38 +92,26 @@
</template>
<template #action="slotProps">
<a-space :size="16">
<a-tooltip
v-for="i in getActions(slotProps)"
<template
v-for="i in getActions(slotProps, 'table')"
:key="i.key"
v-bind="i.tooltip"
>
<a-popconfirm
v-if="i.popConfirm"
v-bind="i.popConfirm"
okText="确定"
cancelText="取消"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
><AIcon :type="i.icon"
/></a-button>
</a-popconfirm>
<a-button
style="padding: 0"
<PermissionButton
:disabled="i.disabled"
:popConfirm="i.popConfirm"
:tooltip="{
...i.tooltip,
}"
@click="i.onClick"
type="link"
v-else
@click="i.onClick && i.onClick(slotProps)"
style="padding: 0px"
:hasPermission="'device/Instance:' + i.key"
>
<a-button
:disabled="i.disabled"
style="padding: 0"
type="link"
<template #icon
><AIcon :type="i.icon"
/></a-button>
</a-button>
</a-tooltip>
/></template>
</PermissionButton>
</template>
</a-space>
</template>
</JTable>