feat: 增加跳转按钮 增加告警定位组件

This commit is contained in:
huanghao1412 2024-07-15 12:52:05 +08:00
parent 93a5a0fcca
commit 1fc035f1b3
17 changed files with 588 additions and 2 deletions

4
.env
View File

@ -3,9 +3,9 @@ VITE_DEV_PORT = '8080'
# development path
# VITE_DEV_PATH = 'http://192.168.0.34:11887'
VITE_DEV_PATH = 'http://192.168.0.34:8102'
VITE_DEV_PATH = 'http://114.115.222.135:9008/'
# VITE_DEV_PATH = 'http://192.168.0.120:3001'
VITE_DEV_TOKEN = 'dd23c593-c823-4eb3-86d0-54ec77c99880'
VITE_DEV_TOKEN = 'e5982f26-54bb-45d8-827a-02bbb42a2eae'
# production path
VITE_PRO_PATH = 'http://192.168.0.235:8177'

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 41.8 47.8" style="enable-background:new 0 0 41.8 47.8;" xml:space="preserve">
<g id="bg">
</g>
<g id="顶栏">
</g>
<g id="楼宇蒙层">
</g>
<g id="内容">
<g>
<ellipse style="opacity:0.5;fill:#F43B42;" cx="20.8" cy="36.8" rx="15.4" ry="7.7"/>
<g>
<ellipse style="fill:none;stroke:#F43B42;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:2.0175,2.0175;" cx="20.8" cy="36.8" rx="20" ry="10"/>
</g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="3.5071" y1="11.6331" x2="37.1067" y2="11.6331">
<stop offset="0" style="stop-color:#F43B42;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#F43B42"/>
<stop offset="1" style="stop-color:#F43B42;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);stroke:#F43B42;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.3,22.4 3.5,11.6 20.3,0.8 37.1,11.6 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="3.5071" y1="24.2332" x2="20.3069" y2="24.2332">
<stop offset="0" style="stop-color:#F43B42;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#F43B42"/>
<stop offset="1" style="stop-color:#F43B42;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);stroke:#F43B42;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.3,22.4 20.3,36.8 3.5,11.6 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="20.3069" y1="24.2332" x2="37.1067" y2="24.2332">
<stop offset="0" style="stop-color:#F43B42;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#F43B42"/>
<stop offset="1" style="stop-color:#F43B42;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_3_);stroke:#F43B42;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.3,22.4 20.3,36.8 37.1,11.6 "/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 41.8 47.5" style="enable-background:new 0 0 41.8 47.5;" xml:space="preserve">
<g id="bg">
</g>
<g id="顶栏">
</g>
<g id="楼宇蒙层">
</g>
<g id="内容">
<g>
<ellipse style="opacity:0.5;fill:#4DCA59;" cx="20.9" cy="36.7" rx="15.4" ry="7.7"/>
<g>
<ellipse style="fill:none;stroke:#4DCA59;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:2.0175,2.0175;" cx="20.9" cy="36.7" rx="20" ry="10"/>
</g>
<g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="3.6473" y1="11.4665" x2="37.2469" y2="11.4665">
<stop offset="0" style="stop-color:#4DCA59;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#4DCA59"/>
<stop offset="1" style="stop-color:#4DCA59;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_1_);stroke:#4DCA59;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.4,22.3 3.6,11.5 20.4,0.7 37.2,11.5 "/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="3.6473" y1="24.0666" x2="20.4471" y2="24.0666">
<stop offset="0" style="stop-color:#4DCA59;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#4DCA59"/>
<stop offset="1" style="stop-color:#4DCA59;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_2_);stroke:#4DCA59;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.4,22.3 20.4,36.7 3.6,11.5 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="20.4471" y1="24.0666" x2="37.2469" y2="24.0666">
<stop offset="0" style="stop-color:#4DCA59;stop-opacity:0.15"/>
<stop offset="0.5" style="stop-color:#4DCA59"/>
<stop offset="1" style="stop-color:#4DCA59;stop-opacity:0.15"/>
</linearGradient>
<polygon style="fill:url(#SVGID_3_);stroke:#4DCA59;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;" points="
20.4,22.3 20.4,36.7 37.2,11.5 "/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,26 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { JumpBtnConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {}
export const customData = {
label: '1号楼',
id: null,
id1: null,
showInterval: true,
}
export default class Config extends PublicConfigClass implements CreateComponentType {
constructor() {
super();
this.attr.w = 100
this.attr.h = 40
this.request.requestInterval = 15
}
public key = JumpBtnConfig.key
public chartConfig = cloneDeep(JumpBtnConfig)
public option = cloneDeep(option)
public customData = cloneDeep(customData)
}

View File

@ -0,0 +1,23 @@
<template>
</template>
<script setup lang="ts">
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import {computed, PropType} from "vue";
import {GlobalThemeJsonType} from "@/settings/chartThemes";
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const config = computed(() => {
return props.optionData
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,27 @@
<template>
<setting-item-box name="名称" alone>
<setting-item name="">
<n-input v-model:value="props.customData.label" size="small" placeholder="请输入"/>
</setting-item>
</setting-item-box>
<setting-item-box name="空间ID" alone>
<setting-item name="空间ID 例如 597">
<n-input-number v-model:value="props.customData.id" size="small" placeholder="请输入"/>
</setting-item>
</setting-item-box>
<setting-item-box name="楼层ID" alone>
<setting-item name="楼层ID 例如 13">
<n-input-number v-model:value="props.customData.id1" size="small" placeholder="请输入"/>
</setting-item>
</setting-item-box>
</template>
<script lang="ts" setup>
import {SettingItemBox, SettingItem} from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const JumpBtnConfig: ConfigType = {
key: 'JumpBtn',
chartKey: 'VJumpBtn',
conKey: 'VCJumpBtn',
// VCD开头
conDataKey: 'VCDJumpBtn',
title: '跳转按钮',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'JumpBtn.png'
}

View File

@ -0,0 +1,185 @@
<template>
<div class="floorBox">
<div class="floor" :class="[errorClassName]" @click.stop="jump"><div class="rect"></div>{{ customData.label }}</div>
</div>
</template>
<script setup lang="ts">
import {computed, PropType, Ref, onMounted, ref, watch, onUnmounted} from "vue";
import { customData as customDataConfig } from './config'
import { CreateComponentType } from '@/packages/index.d'
import { publicInterface } from '@/api/path/business.api'
import {isPreview, postMessageToParent} from '@/utils'
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
import {useOriginStore} from "@/store/modules/originStore/originStore";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const customData: Ref<typeof customDataConfig> = computed(() => {
return props.chartConfig.customData as typeof customDataConfig
})
const originStore = useOriginStore()
const systemConfig = originStore.getOriginStore.user.systemConfig
let alarmLevels: number[] = []
if (systemConfig) {
if (systemConfig['active_alarm_level']) {
for (let i = 0; i < Number(systemConfig['active_alarm_level']); i++) {
alarmLevels.push(i + 1)
}
}
}
let errorClassName = ref('')
const getData = () => {
errorClassName.value = ''
const ids = [customData.value.id]
const param = {
confirm_statuses: ['not'],
ids,
levels: alarmLevels
}
publicInterface('/dcim/dems/device', 'get_space_tree_with_status_v3', param).then(res => {
if (res && res.data) {
errorClassName.value = res.data[0].node_status !== 0 ? 'error' : ''
}
})
}
const jump = () => {
postMessageToParent({
type: 'changeRouterV1',
url: `/dynamicRing/schematicDiagram/${customData.value.id1}`,
query: {
expandKeys: [customData.value.id, customData.value.id1]
}
})
}
watch(() => customData.value.id, getData)
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
getData()
}, number)
}
})
onMounted(() => {
getData()
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
getData()
}, number)
})
onUnmounted(() => {
if(timer) clearInterval(timer as number)
})
</script>
<style lang="scss" scoped>
@keyframes buildingFlash {
from {
background-image: url('~@/assets/images/common/普通定位.svg');
}
to {
background-image: url('~@/assets/images/common/告警定位.svg');
}
}
.floorBox{
width: 100%;
height: 100%;
color: #fff;
white-space: nowrap;
position: relative;
@keyframes alarmFlash1 {
from {
background: linear-gradient(to right, rgb(38, 84, 138), rgba(38, 84, 138, 0));
}
to {
background: linear-gradient(to right, rgb(109, 27, 30), rgba(109, 27, 30, 0));
}
}
@keyframes alarmFlash2 {
from {
background: linear-gradient(to right, rgb(67, 150, 253), rgba(67, 150, 253, 0));
}
to {
background: linear-gradient(to right, rgb(243, 59, 65), rgba(243, 59, 65, 0));
}
}
@keyframes alarmFlash3 {
from {
// background: rgb(67, 150, 253);
background: linear-gradient(to right, rgb(67, 150, 253), rgb(67, 150, 253));
}
to {
background: rgb(243, 59, 65);
background: linear-gradient(to right, rgb(243, 59, 65), rgb(243, 59, 65));
}
}
.floor {
height: 100%;
width: calc(100% - 10px);
position: relative;
cursor: pointer;
background: linear-gradient(to right, rgb(38, 84, 138), rgba(38, 84, 138, 0));
display: flex;
margin-left: 10px;
align-items: center;
.rect {
position: absolute;
top: 0;
left: -6px;
width: 3px;
height: 100%;
background: rgb(67, 150, 253);
margin-right: 3px;
visibility: hidden;
}
&:hover {
//font-size: 17px;
font-weight: bold;
background: linear-gradient(to right, rgb(67, 150, 253), rgba(67, 150, 253, 0));
.rect {
visibility: visible;
}
}
}
.error {
animation: alarmFlash1 1s ease-in-out infinite alternate;
background: linear-gradient(to right, rgb(109, 27, 30), rgba(109, 27, 30, 0));
&:hover {
//font-size: 17px;
font-weight: bold;
animation: alarmFlash1 1s ease-in-out infinite alternate;
background: linear-gradient(to right, rgb(243, 59, 65), rgba(243, 59, 65, 0));
.rect {
height: 100%;
animation: alarmFlash3 1s ease-in-out infinite alternate;
background: rgb(243, 59, 65);
visibility: visible;
}
}
}
}
</style>

View File

@ -0,0 +1,25 @@
import { PublicConfigClass } from '@/packages/public'
import { CreateComponentType } from '@/packages/index.d'
import { PositionConfig } from './index'
import cloneDeep from 'lodash/cloneDeep'
// import logo from '@/assets/logo.png'
export const option = {}
export const customData = {
label: '数据中心',
id: null,
showInterval: true,
}
export default class Config extends PublicConfigClass implements CreateComponentType {
constructor() {
super();
this.attr.w = 100
this.attr.h = 100
this.request.requestInterval = 15
}
public key = PositionConfig.key
public chartConfig = cloneDeep(PositionConfig)
public option = cloneDeep(option)
public customData = cloneDeep(customData)
}

View File

@ -0,0 +1,23 @@
<template>
</template>
<script setup lang="ts">
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import {computed, PropType} from "vue";
import {GlobalThemeJsonType} from "@/settings/chartThemes";
const props = defineProps({
optionData: {
type: Object as PropType<GlobalThemeJsonType>,
required: true
}
})
const config = computed(() => {
return props.optionData
});
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,22 @@
<template>
<setting-item-box name="名称" alone>
<setting-item name="">
<n-input v-model:value="props.customData.label" size="small" placeholder="请输入"/>
</setting-item>
</setting-item-box>
<setting-item-box name="空间ID" alone>
<setting-item name="空间ID 例如 597">
<n-input-number v-model:value="props.customData.id" size="small" placeholder="请输入"/>
</setting-item>
</setting-item-box>
</template>
<script lang="ts" setup>
import {SettingItemBox, SettingItem} from '@/components/Pages/ChartItemSetting'
const props = defineProps(['customData', 'request'])
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,16 @@
import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/CustomComponents/index.d'
export const PositionConfig: ConfigType = {
key: 'Position',
chartKey: 'VPosition',
conKey: 'VCPosition',
// VCD开头
conDataKey: 'VCDPosition',
title: '告警定位',
category: ChatCategoryEnum.CUSTOMCOMPONENTS,
categoryName: ChatCategoryEnumName.CUSTOMCOMPONENTS,
package: PackagesCategoryEnum.CUSTOMCOMPONENTS,
chartFrame: ChartFrameEnum.COMMON,
image: 'Position.png'
}

View File

@ -0,0 +1,129 @@
<template>
<div class="box" style="overflow: visible;">
<div class="label">{{customData.label}}</div>
<div class="position" :class="[errorClassName]"></div>
</div>
</template>
<script setup lang="ts">
import {computed, PropType, Ref, onMounted, ref, watch, onUnmounted} from "vue";
import { customData as customDataConfig } from './config'
import { CreateComponentType } from '@/packages/index.d'
import { publicInterface } from '@/api/path/business.api'
import {isPreview, postMessageToParent} from '@/utils'
import {selectTimeOptions} from "@/views/chart/ContentConfigurations/components/ChartData/index.d";
import {useOriginStore} from "@/store/modules/originStore/originStore";
const props = defineProps({
chartConfig: {
type: Object as PropType<CreateComponentType>,
required: true
}
})
const customData: Ref<typeof customDataConfig> = computed(() => {
return props.chartConfig.customData as typeof customDataConfig
})
const originStore = useOriginStore()
const systemConfig = originStore.getOriginStore.user.systemConfig
let alarmLevels: number[] = []
if (systemConfig) {
if (systemConfig['active_alarm_level']) {
for (let i = 0; i < Number(systemConfig['active_alarm_level']); i++) {
alarmLevels.push(i + 1)
}
}
}
let errorClassName = ref('')
const getData = () => {
errorClassName.value = ''
const ids = [customData.value.id]
const param = {
confirm_statuses: ['not'],
ids,
levels: alarmLevels
}
publicInterface('/dcim/dems/device', 'get_space_tree_with_status_v3', param).then(res => {
if (res && res.data) {
errorClassName.value = res.data[0].node_status !== 0 ? 'error' : ''
}
})
}
watch(() => customData.value.id, getData)
let timer:unknown
watch(() => [props.chartConfig.request.requestInterval, props.chartConfig.request.requestIntervalUnit].join('&&'), v => {
if(!isPreview()) return
if(props.chartConfig.request.requestInterval) {
if(timer) clearInterval(timer as number)
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval
timer = setInterval(() => {
getData()
}, number)
}
})
onMounted(() => {
getData()
if(!isPreview()) return
const obj = selectTimeOptions.find(_ => _.value === props.chartConfig.request.requestIntervalUnit) || {unit: 0}
const unit = obj.unit
const number = unit * props.chartConfig.request.requestInterval!
timer = setInterval(() => {
getData()
}, number)
})
onUnmounted(() => {
if(timer) clearInterval(timer as number)
})
</script>
<style lang="scss" scoped>
@keyframes buildingFlash {
from {
background-image: url('~@/assets/images/common/普通定位.svg');
}
to {
background-image: url('~@/assets/images/common/告警定位.svg');
}
}
.box{
width: 100%;
height: 100%;
position: relative;
.label{
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
height: 24px;
line-height: 24px;
font-size: 16px;
font-weight: bold;
text-align: center;
color: #fff;
white-space: nowrap;
}
.position{
margin-top: 29px;
width: 100%;
height: calc(100% - 29px);
background-image: url('~@/assets/images/common/普通定位.svg');
background-size: 100% 100%;
&.error{
animation: buildingFlash 1s ease-in-out infinite alternate;
background-image: url('~@/assets/images/common/告警定位.svg');
}
}
}
</style>

View File

@ -16,6 +16,8 @@ import { PowerCapacityConfig } from './PowerCapacity'
import { ElectricityConsumptionConfig } from './ElectricityConsumption'
import { DeviceRunningStateConfig } from './DeviceRunningState'
import { TemperatureTop10Config } from './TemperatureTop10'
import { PositionConfig } from './Position'
import { JumpBtnConfig } from './JumpBtn'
export default [
// Theme1Config,
@ -36,4 +38,6 @@ export default [
ElectricityConsumptionConfig,
DeviceRunningStateConfig,
TemperatureTop10Config,
PositionConfig,
JumpBtnConfig,
]

View File

@ -25,6 +25,10 @@ export default ({ mode } : { mode:any }) => defineConfig({
find: '@',
replacement: pathResolve('src')
},
{
find: '~@',
replacement: pathResolve('src')
},
{
find: 'vue-i18n',
replacement: 'vue-i18n/dist/vue-i18n.cjs.js' //解决i8n警告