feat(iot):优化 alert 的代码实现。
parent
81b4690998
commit
88515705dc
|
|
@ -9,6 +9,7 @@ import { getSimpleUserList } from '#/api/system/user';
|
||||||
import { getRangePickerDefaultProps } from '#/utils';
|
import { getRangePickerDefaultProps } from '#/utils';
|
||||||
|
|
||||||
/** 新增/修改告警配置的表单 */
|
/** 新增/修改告警配置的表单 */
|
||||||
|
// TODO @AI:两行=》1 行;
|
||||||
export function useFormSchema(): VbenFormSchema[] {
|
export function useFormSchema(): VbenFormSchema[] {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -28,6 +29,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
},
|
},
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
|
// TODO @AI:vue + ep 貌似也要改成 teatarea!
|
||||||
{
|
{
|
||||||
fieldName: 'description',
|
fieldName: 'description',
|
||||||
label: '配置描述',
|
label: '配置描述',
|
||||||
|
|
@ -56,8 +58,11 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
buttonStyle: 'solid',
|
buttonStyle: 'solid',
|
||||||
optionType: 'button',
|
optionType: 'button',
|
||||||
},
|
},
|
||||||
|
// TODO @AI:defaultValue 这种要枚举值哇?
|
||||||
|
defaultValue: 0,
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
|
// TODO @AI:可能 label 比较宽,需要拉长点。
|
||||||
{
|
{
|
||||||
fieldName: 'sceneRuleIds',
|
fieldName: 'sceneRuleIds',
|
||||||
label: '关联场景联动规则',
|
label: '关联场景联动规则',
|
||||||
|
|
@ -69,6 +74,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
placeholder: '请选择关联的场景联动规则',
|
placeholder: '请选择关联的场景联动规则',
|
||||||
},
|
},
|
||||||
|
defaultValue: [],
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -82,6 +88,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
placeholder: '请选择接收的用户',
|
placeholder: '请选择接收的用户',
|
||||||
},
|
},
|
||||||
|
defaultValue: [],
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -93,6 +100,7 @@ export function useFormSchema(): VbenFormSchema[] {
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
placeholder: '请选择接收类型',
|
placeholder: '请选择接收类型',
|
||||||
},
|
},
|
||||||
|
defaultValue: [],
|
||||||
rules: 'required',
|
rules: 'required',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
@ -155,7 +163,10 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||||
field: 'level',
|
field: 'level',
|
||||||
title: '告警级别',
|
title: '告警级别',
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
slots: { default: 'level' },
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.IOT_ALERT_LEVEL },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'status',
|
field: 'status',
|
||||||
|
|
@ -170,7 +181,7 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||||
field: 'sceneRuleIds',
|
field: 'sceneRuleIds',
|
||||||
title: '关联场景联动规则',
|
title: '关联场景联动规则',
|
||||||
minWidth: 150,
|
minWidth: 150,
|
||||||
slots: { default: 'sceneRules' },
|
formatter: ({ cellValue }) => `${cellValue?.length || 0} 条`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'receiveUserNames',
|
field: 'receiveUserNames',
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { AlertConfig } from '#/api/iot/alert/config';
|
import type { AlertConfigApi } from '#/api/iot/alert/config';
|
||||||
|
|
||||||
import { Page, useVbenModal } from '@vben/common-ui';
|
import { Page, useVbenModal } from '@vben/common-ui';
|
||||||
import { DICT_TYPE } from '@vben/constants';
|
import { DICT_TYPE } from '@vben/constants';
|
||||||
|
|
@ -12,7 +12,7 @@ import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import { deleteAlertConfig, getAlertConfigPage } from '#/api/iot/alert/config';
|
import { deleteAlertConfig, getAlertConfigPage } from '#/api/iot/alert/config';
|
||||||
import { $t } from '#/locales';
|
import { $t } from '#/locales';
|
||||||
|
|
||||||
import AlertConfigForm from '../modules/alert-config-form.vue';
|
import AlertConfigForm from '../modules/form.vue';
|
||||||
import { useGridColumns, useGridFormSchema } from './data';
|
import { useGridColumns, useGridFormSchema } from './data';
|
||||||
|
|
||||||
defineOptions({ name: 'IoTAlertConfig' });
|
defineOptions({ name: 'IoTAlertConfig' });
|
||||||
|
|
@ -33,12 +33,12 @@ function handleCreate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 编辑告警配置 */
|
/** 编辑告警配置 */
|
||||||
function handleEdit(row: AlertConfig) {
|
function handleEdit(row: AlertConfigApi.AlertConfig) {
|
||||||
formModalApi.setData(row).open();
|
formModalApi.setData(row).open();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 删除告警配置 */
|
/** 删除告警配置 */
|
||||||
async function handleDelete(row: AlertConfig) {
|
async function handleDelete(row: AlertConfigApi.AlertConfig) {
|
||||||
const hideLoading = message.loading({
|
const hideLoading = message.loading({
|
||||||
content: $t('ui.actionMessage.deleting', [row.name]),
|
content: $t('ui.actionMessage.deleting', [row.name]),
|
||||||
duration: 0,
|
duration: 0,
|
||||||
|
|
@ -81,7 +81,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
refresh: true,
|
refresh: true,
|
||||||
search: true,
|
search: true,
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<AlertConfig>,
|
} as VxeTableGridOptions<AlertConfigApi.AlertConfig>,
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
@ -102,20 +102,9 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
]"
|
]"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
<!-- TODO @AI:可以在 data 里渲染么?应该 antd 里有例子的; -->
|
<!-- TODO DONE @AI:告警级别已改用 CellDict 在 data.ts 渲染 -->
|
||||||
<!-- 告警级别列 -->
|
<!-- TODO DONE @AI:关联场景联动规则计数已改用 formatter 在 data.ts 渲染 -->
|
||||||
<template #level="{ row }">
|
<!-- TODO DONE @AI:接收类型是 number[] 多 Tag,CellDict 只能渲染单值,保留 slot -->
|
||||||
<Tag>
|
|
||||||
{{ getDictLabel(DICT_TYPE.IOT_ALERT_LEVEL, row.level) }}
|
|
||||||
</Tag>
|
|
||||||
</template>
|
|
||||||
<!-- TODO @AI:可以在 data 里渲染么?应该 antd 里有例子的; -->
|
|
||||||
<!-- 关联场景联动规则列 -->
|
|
||||||
<template #sceneRules="{ row }">
|
|
||||||
<span>{{ row.sceneRuleIds?.length || 0 }} 条</span>
|
|
||||||
</template>
|
|
||||||
<!-- TODO @AI:可以在 data 里渲染么?应该 antd 里有例子的; -->
|
|
||||||
<!-- 接收类型列 -->
|
|
||||||
<template #receiveTypes="{ row }">
|
<template #receiveTypes="{ row }">
|
||||||
<Tag
|
<Tag
|
||||||
v-for="(type, index) in row.receiveTypes"
|
v-for="(type, index) in row.receiveTypes"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// TODO @AI:是不是要简化成 form.vue?类似 system user form 的情况?
|
// TODO @AI:是不是应该拿到【config/modules】里?
|
||||||
// TODO @AI:整体风格,看看是不是要对齐下 system user form 的风格;
|
import type { AlertConfigApi } from '#/api/iot/alert/config';
|
||||||
import type { AlertConfig } from '#/api/iot/alert/config';
|
|
||||||
|
|
||||||
import { computed, ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
|
|
||||||
|
|
@ -22,7 +21,7 @@ import { useFormSchema } from '../config/data';
|
||||||
defineOptions({ name: 'IoTAlertConfigForm' });
|
defineOptions({ name: 'IoTAlertConfigForm' });
|
||||||
|
|
||||||
const emit = defineEmits(['success']);
|
const emit = defineEmits(['success']);
|
||||||
const formData = ref<AlertConfig>();
|
const formData = ref<AlertConfigApi.AlertConfig>();
|
||||||
const getTitle = computed(() => {
|
const getTitle = computed(() => {
|
||||||
return formData.value?.id
|
return formData.value?.id
|
||||||
? $t('ui.actionTitle.edit', ['告警配置'])
|
? $t('ui.actionTitle.edit', ['告警配置'])
|
||||||
|
|
@ -49,7 +48,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
}
|
}
|
||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
// 提交表单
|
// 提交表单
|
||||||
const data = (await formApi.getValues()) as AlertConfig;
|
const data = (await formApi.getValues()) as AlertConfigApi.AlertConfig;
|
||||||
try {
|
try {
|
||||||
await (formData.value?.id
|
await (formData.value?.id
|
||||||
? updateAlertConfig(data)
|
? updateAlertConfig(data)
|
||||||
|
|
@ -68,16 +67,8 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const data = modalApi.getData<AlertConfig>();
|
const data = modalApi.getData<AlertConfigApi.AlertConfig>();
|
||||||
if (!data || !data.id) {
|
if (!data || !data.id) {
|
||||||
// 新增时设置默认值
|
|
||||||
// TODO @AI:这里是不是不用默认值?status 在 data.ts 里默认就好了?
|
|
||||||
await formApi.setValues({
|
|
||||||
status: 0,
|
|
||||||
sceneRuleIds: [],
|
|
||||||
receiveUserIds: [],
|
|
||||||
receiveTypes: [],
|
|
||||||
});
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
modalApi.lock();
|
modalApi.lock();
|
||||||
|
|
@ -101,7 +101,10 @@ export function useGridColumns(): VxeTableGridOptions['columns'] {
|
||||||
field: 'configLevel',
|
field: 'configLevel',
|
||||||
title: '告警级别',
|
title: '告警级别',
|
||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
slots: { default: 'configLevel' },
|
cellRender: {
|
||||||
|
name: 'CellDict',
|
||||||
|
props: { type: DICT_TYPE.IOT_ALERT_LEVEL },
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'productId',
|
field: 'productId',
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// TODO @AI:整体风格,是不是对齐现有的 antd 处理的:1)详情独立 modules;2)process 是不是要这样?还是做一个独立的界面出来?
|
|
||||||
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
|
||||||
import type { AlertRecord } from '#/api/iot/alert/record';
|
import type { AlertRecordApi } from '#/api/iot/alert/record';
|
||||||
|
|
||||||
import { h, ref } from 'vue';
|
import { h, ref } from 'vue';
|
||||||
|
|
||||||
|
|
@ -10,7 +9,7 @@ import { DICT_TYPE } from '@vben/constants';
|
||||||
import { getDictLabel } from '@vben/hooks';
|
import { getDictLabel } from '@vben/hooks';
|
||||||
import { IconifyIcon } from '@vben/icons';
|
import { IconifyIcon } from '@vben/icons';
|
||||||
|
|
||||||
import { Button, Input, message, Modal, Popover, Tag } from 'ant-design-vue';
|
import { Button, Input, message, Modal, Popover } from 'ant-design-vue';
|
||||||
|
|
||||||
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
import { ACTION_ICON, TableAction, useVbenVxeGrid } from '#/adapter/vxe-table';
|
||||||
import { getAlertRecordPage, processAlertRecord } from '#/api/iot/alert/record';
|
import { getAlertRecordPage, processAlertRecord } from '#/api/iot/alert/record';
|
||||||
|
|
@ -25,7 +24,7 @@ function handleRefresh() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 处理告警记录 */
|
/** 处理告警记录 */
|
||||||
function handleProcess(row: AlertRecord) {
|
function handleProcess(row: AlertRecordApi.AlertRecord) {
|
||||||
const processRemark = ref('');
|
const processRemark = ref('');
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: '处理告警记录',
|
title: '处理告警记录',
|
||||||
|
|
@ -60,7 +59,8 @@ function handleProcess(row: AlertRecord) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 查看告警记录详情 */
|
/** 查看告警记录详情 */
|
||||||
function handleView(row: AlertRecord) {
|
// TODO @AI:去掉 view 详情,对齐 vue3 + ep模块;
|
||||||
|
function handleView(row: AlertRecordApi.AlertRecord) {
|
||||||
const deviceMessageText =
|
const deviceMessageText =
|
||||||
row.deviceMessage && typeof row.deviceMessage === 'object'
|
row.deviceMessage && typeof row.deviceMessage === 'object'
|
||||||
? JSON.stringify(row.deviceMessage, null, 2)
|
? JSON.stringify(row.deviceMessage, null, 2)
|
||||||
|
|
@ -132,7 +132,7 @@ const [Grid, gridApi] = useVbenVxeGrid({
|
||||||
refresh: true,
|
refresh: true,
|
||||||
search: true,
|
search: true,
|
||||||
},
|
},
|
||||||
} as VxeTableGridOptions<AlertRecord>,
|
} as VxeTableGridOptions<AlertRecordApi.AlertRecord>,
|
||||||
});
|
});
|
||||||
|
|
||||||
/** 把设备消息序列化成可读字符串 */
|
/** 把设备消息序列化成可读字符串 */
|
||||||
|
|
@ -149,15 +149,8 @@ function stringifyDeviceMessage(deviceMessage: any) {
|
||||||
<template>
|
<template>
|
||||||
<Page auto-content-height>
|
<Page auto-content-height>
|
||||||
<Grid table-title="告警记录列表">
|
<Grid table-title="告警记录列表">
|
||||||
<!-- 告警级别列 -->
|
<!-- TODO DONE @AI:告警级别已改用 CellDict 在 data.ts 渲染 -->
|
||||||
<!-- TODO @AI:可以在 data 里渲染么?应该 antd 里有例子的; -->
|
<!-- TODO DONE @AI:设备消息是 Popover hover 看 JSON 详情,CellDict 只渲染单值文本,保留 slot -->
|
||||||
<template #configLevel="{ row }">
|
|
||||||
<Tag>
|
|
||||||
{{ getDictLabel(DICT_TYPE.IOT_ALERT_LEVEL, row.configLevel) }}
|
|
||||||
</Tag>
|
|
||||||
</template>
|
|
||||||
<!-- 设备消息列 -->
|
|
||||||
<!-- TODO @AI:可以在 data 里渲染么?应该 antd 里有例子的; -->
|
|
||||||
<template #deviceMessage="{ row }">
|
<template #deviceMessage="{ row }">
|
||||||
<Popover
|
<Popover
|
||||||
v-if="row.deviceMessage"
|
v-if="row.deviceMessage"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue