Showing
5 changed files
with
99 additions
and
107 deletions
| 1 | import { cloneDeep } from 'lodash-es' | 1 | import { cloneDeep } from 'lodash-es' |
| 2 | -import { TableColumnFieldEnum } from './types' | ||
| 3 | import { AlarmListConfig } from '.' | 2 | import { AlarmListConfig } from '.' |
| 4 | import { ModeEnum } from '@/enums/modeEnum' | 3 | import { ModeEnum } from '@/enums/modeEnum' |
| 5 | import type { | 4 | import type { |
| 6 | CreateComponentParamsType, | 5 | CreateComponentParamsType, |
| 7 | CreateComponentType, | 6 | CreateComponentType, |
| 8 | } from '@/core/Library/types' | 7 | } from '@/core/Library/types' |
| 9 | -import type { BasicColumn } from '@/components/Table' | ||
| 10 | -import type { CodeTypeEnum, ContentDataFieldsEnum } from '@/enums/datasource' | ||
| 11 | 8 | ||
| 12 | -export const tableColumns: BasicColumn[] = [ | ||
| 13 | - { | ||
| 14 | - title: '设备', | ||
| 15 | - width: 200, | ||
| 16 | - key: TableColumnFieldEnum.DEVICE_ID, | ||
| 17 | - dataIndex: TableColumnFieldEnum.DEVICE_ID, | ||
| 18 | - }, | ||
| 19 | - { | ||
| 20 | - title: '操作', | ||
| 21 | - key: 'action', | ||
| 22 | - }, | ||
| 23 | -] | ||
| 24 | - | ||
| 25 | -export interface TableRecordItemType { | ||
| 26 | - uuid: string | ||
| 27 | - [TableColumnFieldEnum.DEVICE_ID]?: Nullable<string> | ||
| 28 | - [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | ||
| 29 | -} | ||
| 30 | - | ||
| 31 | -// 告警状态 | ||
| 32 | -export const alarmStatus = [ | ||
| 33 | - { | ||
| 34 | - label: '清除未确认', | ||
| 35 | - value: 'CLEARED_UNACK', | ||
| 36 | - color: 'red', | ||
| 37 | - }, | ||
| 38 | - { | ||
| 39 | - label: '激活未确认', | ||
| 40 | - value: 'ACTIVE_UNACK', | ||
| 41 | - color: 'orange', | ||
| 42 | - }, | ||
| 43 | - { | ||
| 44 | - label: '清除已确认', | ||
| 45 | - value: 'CLEARED_ACK', | ||
| 46 | - color: 'cyan', | ||
| 47 | - }, | ||
| 48 | - { | ||
| 49 | - label: '激活已确认', | ||
| 50 | - value: 'ACTIVE_ACK', | ||
| 51 | - color: 'green', | ||
| 52 | - }, | ||
| 53 | -] | ||
| 54 | - | ||
| 55 | -export interface alarmListInterface { | ||
| 56 | - deviceName: string | ||
| 57 | - deviceAlias: string | ||
| 58 | - status: string | ||
| 59 | - startTs: string | ||
| 60 | -} | ||
| 61 | - | ||
| 62 | -// 模拟假数据 | ||
| 63 | -const alarmList = Array.from({ length: 20 }, (_, index) => ({ | ||
| 64 | - deviceName: `示例设备${index + 1}`, | ||
| 65 | - deviceAlias: `示例设备${index + 1}`, | ||
| 66 | - startTs: `2023-10-1${index + 1} 11:19:41`, | ||
| 67 | - status: alarmStatus.map(item => item.value)[ | ||
| 68 | - Math.floor(Math.random() * alarmStatus.length) | ||
| 69 | - ], | ||
| 70 | -})) | ||
| 71 | - | ||
| 72 | -// 组件配置项 | ||
| 73 | export const options = { | 9 | export const options = { |
| 74 | - alarmList, | ||
| 75 | - scroll: false, | ||
| 76 | - interval: 0, | 10 | + |
| 77 | } | 11 | } |
| 78 | 12 | ||
| 79 | export default class Config implements CreateComponentType { | 13 | export default class Config implements CreateComponentType { |
| 80 | public key: string = AlarmListConfig.key | 14 | public key: string = AlarmListConfig.key |
| 81 | 15 | ||
| 82 | - public presetOption = cloneDeep(options as any) | 16 | + public presetOption = cloneDeep(options) |
| 83 | 17 | ||
| 84 | public mode = ModeEnum.EDIT | 18 | public mode = ModeEnum.EDIT |
| 85 | 19 |
| 1 | <script setup lang="ts"> | 1 | <script setup lang="ts"> |
| 2 | import { Button, Divider } from 'ant-design-vue' | 2 | import { Button, Divider } from 'ant-design-vue' |
| 3 | -import { onMounted, unref } from 'vue' | 3 | +import { onMounted, ref, unref } from 'vue' |
| 4 | import { AlarmListFieldsEnum, formSchemas } from './form.config' | 4 | import { AlarmListFieldsEnum, formSchemas } from './form.config' |
| 5 | import { FormLayoutEnum } from '@/components/Form/src/enum' | 5 | import { FormLayoutEnum } from '@/components/Form/src/enum' |
| 6 | import { BasicForm, useForm } from '@/components/Form' | 6 | import { BasicForm, useForm } from '@/components/Form' |
| @@ -10,6 +10,7 @@ import type { ConfigComponentProps } from '@/core/Library/types' | @@ -10,6 +10,7 @@ import type { ConfigComponentProps } from '@/core/Library/types' | ||
| 10 | import { dateUtil } from '@/utils/dateUtil' | 10 | import { dateUtil } from '@/utils/dateUtil' |
| 11 | import { DateFormatEnum } from '@/enums/timeEnum' | 11 | import { DateFormatEnum } from '@/enums/timeEnum' |
| 12 | import type { AlarmListOptionType } from '@/api/node/model' | 12 | import type { AlarmListOptionType } from '@/api/node/model' |
| 13 | +import { useSavePageContent } from '@/core/Library/hook/useSavePageContent' | ||
| 13 | 14 | ||
| 14 | const props = defineProps<ConfigComponentProps>() | 15 | const props = defineProps<ConfigComponentProps>() |
| 15 | 16 | ||
| @@ -17,6 +18,8 @@ defineEmits(['register']) | @@ -17,6 +18,8 @@ defineEmits(['register']) | ||
| 17 | 18 | ||
| 18 | const { createMessage } = useMessage() | 19 | const { createMessage } = useMessage() |
| 19 | 20 | ||
| 21 | +const loading = ref(false) | ||
| 22 | + | ||
| 20 | const nodeDataActinType = useNodeData({ cell: props.cell!, immediate: true }) | 23 | const nodeDataActinType = useNodeData({ cell: props.cell!, immediate: true }) |
| 21 | 24 | ||
| 22 | const { getNodeData, getNodeAllData, saveNodeAllData } = nodeDataActinType | 25 | const { getNodeData, getNodeAllData, saveNodeAllData } = nodeDataActinType |
| @@ -52,14 +55,23 @@ const setFieldsValue = (value: Recordable) => { | @@ -52,14 +55,23 @@ const setFieldsValue = (value: Recordable) => { | ||
| 52 | }) | 55 | }) |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 58 | +const { savePageContent } = useSavePageContent() | ||
| 59 | + | ||
| 55 | const handleSave = async () => { | 60 | const handleSave = async () => { |
| 56 | - const validateFail = await validate() | ||
| 57 | - if (!validateFail) return | ||
| 58 | - const value = getFieldsValue() as AlarmListOptionType | ||
| 59 | - await saveNodeAllData({ | ||
| 60 | - dataSourceJson: { alarmListOption: value }, | ||
| 61 | - }) | ||
| 62 | - createMessage.success('保存成功') | 61 | + try { |
| 62 | + loading.value = true | ||
| 63 | + const validateFail = await validate() | ||
| 64 | + if (!validateFail) return | ||
| 65 | + const value = getFieldsValue() as AlarmListOptionType | ||
| 66 | + await saveNodeAllData({ | ||
| 67 | + dataSourceJson: { alarmListOption: value }, | ||
| 68 | + }) | ||
| 69 | + createMessage.success('保存成功') | ||
| 70 | + savePageContent() | ||
| 71 | + } | ||
| 72 | + finally { | ||
| 73 | + loading.value = false | ||
| 74 | + } | ||
| 63 | } | 75 | } |
| 64 | 76 | ||
| 65 | onMounted(async () => { | 77 | onMounted(async () => { |
| @@ -76,7 +88,7 @@ onMounted(async () => { | @@ -76,7 +88,7 @@ onMounted(async () => { | ||
| 76 | </Divider> | 88 | </Divider> |
| 77 | <div class="m-4"> | 89 | <div class="m-4"> |
| 78 | <BasicForm @register="registerForm" /> | 90 | <BasicForm @register="registerForm" /> |
| 79 | - <Button class="w-full" type="primary" @click="handleSave"> | 91 | + <Button class="w-full" type="primary" :loading="loading" @click="handleSave"> |
| 80 | 保存 | 92 | 保存 |
| 81 | </Button> | 93 | </Button> |
| 82 | </div> | 94 | </div> |
| 1 | import { unref } from 'vue' | 1 | import { unref } from 'vue' |
| 2 | import dayjs from 'dayjs' | 2 | import dayjs from 'dayjs' |
| 3 | +import { TableColumnFieldEnum } from './types' | ||
| 3 | import { getListByDeviceProfileIds } from '@/api/device' | 4 | import { getListByDeviceProfileIds } from '@/api/device' |
| 4 | import type { DeviceItemType } from '@/api/device/model' | 5 | import type { DeviceItemType } from '@/api/device/model' |
| 5 | import type { FormSchema } from '@/components/Form' | 6 | import type { FormSchema } from '@/components/Form' |
| 6 | import { ComponentEnum } from '@/components/Form/src/enum' | 7 | import { ComponentEnum } from '@/components/Form/src/enum' |
| 7 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' | 8 | import { useContentDataStoreWithOut } from '@/store/modules/contentData' |
| 8 | import { DateFormatEnum } from '@/enums/timeEnum' | 9 | import { DateFormatEnum } from '@/enums/timeEnum' |
| 10 | +import type { BasicColumn } from '@/components/Table' | ||
| 11 | +import type { CodeTypeEnum, ContentDataFieldsEnum } from '@/enums/datasource' | ||
| 9 | 12 | ||
| 10 | const contentDataStore = useContentDataStoreWithOut() | 13 | const contentDataStore = useContentDataStoreWithOut() |
| 11 | 14 | ||
| 15 | +export const tableColumns: BasicColumn[] = [ | ||
| 16 | + { | ||
| 17 | + title: '设备', | ||
| 18 | + width: 200, | ||
| 19 | + key: TableColumnFieldEnum.DEVICE_ID, | ||
| 20 | + dataIndex: TableColumnFieldEnum.DEVICE_ID, | ||
| 21 | + }, | ||
| 22 | + { | ||
| 23 | + title: '操作', | ||
| 24 | + key: 'action', | ||
| 25 | + }, | ||
| 26 | +] | ||
| 27 | + | ||
| 28 | +export interface TableRecordItemType { | ||
| 29 | + uuid: string | ||
| 30 | + [TableColumnFieldEnum.DEVICE_ID]?: Nullable<string> | ||
| 31 | + [ContentDataFieldsEnum.CODE_TYPE]?: Nullable<CodeTypeEnum> | ||
| 32 | +} | ||
| 33 | + | ||
| 34 | +// 告警状态 | ||
| 35 | +export const alarmStatus = [ | ||
| 36 | + { | ||
| 37 | + label: '清除未确认', | ||
| 38 | + value: 'CLEARED_UNACK', | ||
| 39 | + color: 'red', | ||
| 40 | + }, | ||
| 41 | + { | ||
| 42 | + label: '激活未确认', | ||
| 43 | + value: 'ACTIVE_UNACK', | ||
| 44 | + color: 'orange', | ||
| 45 | + }, | ||
| 46 | + { | ||
| 47 | + label: '清除已确认', | ||
| 48 | + value: 'CLEARED_ACK', | ||
| 49 | + color: 'cyan', | ||
| 50 | + }, | ||
| 51 | + { | ||
| 52 | + label: '激活已确认', | ||
| 53 | + value: 'ACTIVE_ACK', | ||
| 54 | + color: 'green', | ||
| 55 | + }, | ||
| 56 | +] | ||
| 57 | + | ||
| 58 | +export interface alarmListInterface { | ||
| 59 | + deviceName: string | ||
| 60 | + deviceAlias: string | ||
| 61 | + status: string | ||
| 62 | + startTs: string | ||
| 63 | +} | ||
| 64 | + | ||
| 12 | /** | 65 | /** |
| 13 | * 告警列表相关枚举 | 66 | * 告警列表相关枚举 |
| 14 | */ | 67 | */ |
| @@ -2,13 +2,13 @@ | @@ -2,13 +2,13 @@ | ||
| 2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' | 2 | import { computed, nextTick, onMounted, reactive, unref } from 'vue' |
| 3 | import { Divider, Tag } from 'ant-design-vue' | 3 | import { Divider, Tag } from 'ant-design-vue' |
| 4 | import Vue3SeamlessScroll from 'vue3-seamless-scroll/package/Vue3SeamlessScroll' | 4 | import Vue3SeamlessScroll from 'vue3-seamless-scroll/package/Vue3SeamlessScroll' |
| 5 | -import type { alarmListInterface } from './config' | ||
| 6 | -import { options } from './config' | ||
| 7 | import { useAlarmList } from './useAlarmList.hook' | 5 | import { useAlarmList } from './useAlarmList.hook' |
| 6 | +import { type alarmListInterface, alarmStatus } from './form.config' | ||
| 8 | import { fetchAlarmList } from '@/api/alarm' | 7 | import { fetchAlarmList } from '@/api/alarm' |
| 9 | import type { CreateComponentType } from '@/core/Library/types' | 8 | import type { CreateComponentType } from '@/core/Library/types' |
| 10 | import { useContentDataStore } from '@/store/modules/contentData' | 9 | import { useContentDataStore } from '@/store/modules/contentData' |
| 11 | import { isLightboxMode } from '@/utils/env' | 10 | import { isLightboxMode } from '@/utils/env' |
| 11 | +import { formatToDateTime } from '@/utils/dateUtil' | ||
| 12 | 12 | ||
| 13 | const props = defineProps<{ | 13 | const props = defineProps<{ |
| 14 | config: CreateComponentType | 14 | config: CreateComponentType |
| @@ -47,7 +47,7 @@ const initFetchAlarmList = async () => { | @@ -47,7 +47,7 @@ const initFetchAlarmList = async () => { | ||
| 47 | const { alarmListOption } = dataSourceJson | 47 | const { alarmListOption } = dataSourceJson |
| 48 | if (!alarmListOption) return | 48 | if (!alarmListOption) return |
| 49 | const { startTime, endTime, deviceId, interval, autoPlay, polling } | 49 | const { startTime, endTime, deviceId, interval, autoPlay, polling } |
| 50 | - = alarmListOption | 50 | + = alarmListOption |
| 51 | 51 | ||
| 52 | const resp = (await fetchAlarmList({ | 52 | const resp = (await fetchAlarmList({ |
| 53 | startTime, | 53 | startTime, |
| @@ -72,44 +72,39 @@ onMounted(async () => { | @@ -72,44 +72,39 @@ onMounted(async () => { | ||
| 72 | setInterval(initFetchAlarmList, initOptions.polling * 1000) | 72 | setInterval(initFetchAlarmList, initOptions.polling * 1000) |
| 73 | } | 73 | } |
| 74 | else { | 74 | else { |
| 75 | - // 设计模式 | ||
| 76 | - for (const i in options) Reflect.set(initOptions, i, (options as any)[i]) | 75 | + Object.assign(initOptions, { |
| 76 | + scroll: false, | ||
| 77 | + interval: 0, | ||
| 78 | + // 模拟假数据 | ||
| 79 | + alarmList: Array.from({ length: 20 }, (_, index) => ({ | ||
| 80 | + deviceName: `示例设备${index + 1}`, | ||
| 81 | + deviceAlias: `示例设备${index + 1}`, | ||
| 82 | + startTs: formatToDateTime(), | ||
| 83 | + status: alarmStatus.map(item => item.value)[ | ||
| 84 | + Math.floor(Math.random() * alarmStatus.length) | ||
| 85 | + ], | ||
| 86 | + })), | ||
| 87 | + }) | ||
| 77 | } | 88 | } |
| 78 | }) | 89 | }) |
| 79 | </script> | 90 | </script> |
| 80 | 91 | ||
| 81 | <template> | 92 | <template> |
| 82 | - <div | ||
| 83 | - class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll" | ||
| 84 | - > | 93 | + <div class="seamless-scroll w-full h-full flex justify-center items-center overflow-y-scroll"> |
| 85 | <Vue3SeamlessScroll | 94 | <Vue3SeamlessScroll |
| 86 | - v-model="initOptions.scroll" | ||
| 87 | - :single-wait-time="initOptions.interval" | ||
| 88 | - :list="initOptions.alarmList" | ||
| 89 | - :limit-scroll-num="10" | ||
| 90 | - :is-rem-unit="true" | ||
| 91 | - :delay="10" | ||
| 92 | - :wheel="true" | ||
| 93 | - hover | ||
| 94 | - :style="{ | 95 | + v-model="initOptions.scroll" :single-wait-time="initOptions.interval" |
| 96 | + :list="initOptions.alarmList" :limit-scroll-num="10" :is-rem-unit="true" :delay="10" :wheel="true" hover :style="{ | ||
| 95 | width: `${getCellBounds.width}px`, | 97 | width: `${getCellBounds.width}px`, |
| 96 | height: `${getCellBounds.height}px`, | 98 | height: `${getCellBounds.height}px`, |
| 97 | }" | 99 | }" |
| 98 | > | 100 | > |
| 99 | - <div | ||
| 100 | - v-for="(item, index) in initOptions.alarmList" | ||
| 101 | - :key="index" | ||
| 102 | - class="flex flex-col items-start h-15 px-2" | ||
| 103 | - > | 101 | + <div v-for="(item, index) in initOptions.alarmList" :key="index" class="flex flex-col items-start h-15 px-2"> |
| 104 | <p class="text-xs"> | 102 | <p class="text-xs"> |
| 105 | 设备:{{ item.deviceAlias || item.deviceName }} | 103 | 设备:{{ item.deviceAlias || item.deviceName }} |
| 106 | </p> | 104 | </p> |
| 107 | <div class="flex items-center justify-between -mt-2"> | 105 | <div class="flex items-center justify-between -mt-2"> |
| 108 | <span class="text-xs">时间:{{ item.startTs }}</span> | 106 | <span class="text-xs">时间:{{ item.startTs }}</span> |
| 109 | - <Tag | ||
| 110 | - class="ml-2 text-xs" | ||
| 111 | - :color="byStatusFindLabel(item.status, 'color')" | ||
| 112 | - > | 107 | + <Tag class="ml-2 text-xs" :color="byStatusFindLabel(item.status, 'color')"> |
| 113 | {{ byStatusFindLabel(item.status, "") }} | 108 | {{ byStatusFindLabel(item.status, "") }} |
| 114 | </Tag> | 109 | </Tag> |
| 115 | </div> | 110 | </div> |
| @@ -122,6 +117,7 @@ onMounted(async () => { | @@ -122,6 +117,7 @@ onMounted(async () => { | ||
| 122 | <style scoped lang="less"> | 117 | <style scoped lang="less"> |
| 123 | .seamless-scroll::-webkit-scrollbar { | 118 | .seamless-scroll::-webkit-scrollbar { |
| 124 | display: none; | 119 | display: none; |
| 120 | + | ||
| 125 | .divider { | 121 | .divider { |
| 126 | height: 0.3px; | 122 | height: 0.3px; |
| 127 | background-color: black; | 123 | background-color: black; |