自定义 Notification 通知提醒框
通常在开发中Ant Design Vue中的Notification 通知提醒框不满足开发需求,此时就需要自己去封装组件了。本示例适用于vue3项目,当然也可以改成vue2。
一、封装组件
<template>
<div>
<!-- <a-button @click="click">告警模拟</a-button> -->
<!-- 消息主体部分 -->
<div v-for="item in divList" :key="item">
<div class="notification-style" :id="item.key">
<div class="title-content">
<div>告警标题</div>
<Icon
icon="iconoir:voice-error"
v-if="!soundSwitch"
@click="soundClick(false, item.key)"
></Icon>
<Icon
icon="iconoir:voice-ok"
color="#1890ff"
v-if="soundSwitch"
@click="soundClick(true, item.key)"
></Icon>
</div>
<div
> 6#CLP_Slora变电站3#逆变器于{{
item.time
}}存在温度过低问题,请确认</div
>
<div class="button-content">
<a-button class="button-style" type="primary">查看</a-button>
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { notification } from 'ant-design-vue';
import { Icon } from '/@/components/Icon';
import { defineComponent, ref, unref, onMounted, nextTick, onBeforeUnmount } from 'vue';
import publicFun from '/@/utils/publicFun';
export default defineComponent({
name: 'LayoutContent',
components: { Icon },
setup() {
// 音频组件实例化
const audios = ref<any | HTMLElement>(null);
// 音频组件显示隐藏
const audioVisible = ref(false);
// 音频组件声音开关
const soundSwitch = ref(true);
const newKey = ref(new Date().getTime());
// 消息列表
const divList = ref([]);
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description1: 音频组件的播放
*/
const startPlay = () => {
console.log('audios', audios.value.play());
audios.value.currentTime = 0; //从头开始播放提示音
audios.value.play(); //播放
};
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description1: 声音图标的点击播放与暂停
*/
const soundClick = (e, key) => {
soundSwitch.value = !e;
// 获取当前告警实例
const box = document.getElementById(key + '1');
if (!e) {
box.play(); //播放
} else {
box.pause(); //暂停
}
// console.log('audios', audios.value.play());
// audios.value.currentTime = 0; //从头开始播放提示音
// audios.value.play(); //播放
};
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description: 模拟webstockt实时推送
*/
// setInterval(() => {
// click();
// }, 6000);
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description: 模拟webstockt推送后事件
*/
const click = () => {
// startPlay()
let nowTime = new Date().getTime();
let topIndex = divList.value.length * 130;
let nowTimeStr = publicFun.getStandardTime(new Date());
divList.value.push({ key: nowTime, label: '', time: nowTimeStr });
// 生成一个audio元素
var audio = document.createElement('audio');
audio.id = nowTime + '1';
audio.controls = false;
var start=0
var times=3
audio.addEventListener('ended',()=>{
audio.play()
start++
start==times&&audio.pause()
});
audio.autoplay = true;
audio.src = '/@/assets/audio/police.mp3';
nextTick(() => {
const box = document.getElementById(nowTime);
box.style.top = topIndex + 'px';
});
};
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description1: 声音播放完成后事件
*/
const palyFunction = (audio) => {
audio.autoplay = true;
for (let i = 0; i < 4; i++) {}
console.log('声音播放完成后事件声音播放完成后事件');
};
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description: setInterval实时循环消息列表,改变列表状态
*/
const interval = setInterval(() => {
if (divList.value.length > 0) {
let list = [];
divList.value.forEach((item, index) => {
let implement = true;
if (document.getElementById(item.key)) {
// 默认4秒时改变div样式
if (new Date().getTime() - item.key >= 4000) {
const box = document.getElementById(item.key);
box.className = 'notification-styles';
}
// 默认进行0.2秒class动画
if (new Date().getTime() - item.key >= 4200) {
// 删除div
document.getElementById(item.key)?.remove();
document.getElementById(item.key + '1')?.remove();
// 改变状态
implement = false;
}
if (implement) {
let topIndex = index * 130;
const box = document.getElementById(item.key);
box.style.top = topIndex + 'px';
list.push(item);
}
}
});
divList.value = list;
}
}, 200);
onBeforeUnmount(() => {
clearInterval(interval);
if (divList.value.length > 0) {
divList.value.forEach((item) => {
document.getElementById(item.key)?.remove();
document.getElementById(item.key + '1')?.remove();
});
}
});
return {
audios,
newKey,
audioVisible,
soundSwitch,
click,
divList,
soundClick,
};
},
});
</script>
<style lang="less">
@prefix-cls: ~'@{namespace}-layout-content';
.@{prefix-cls} {
position: relative;
flex: 1 1 auto;
min-height: 0;
&.fixed {
width: 1200px;
margin: 0 auto;
}
&-loading {
position: absolute;
top: 200px;
z-index: @page-loading-z-index;
}
}
.notification-style {
width: 384px;
height: 116px;
max-width: calc(100vw - 24px * 2);
margin-left: auto;
position: absolute;
top: 0px;
right: 24px;
z-index: 10;
margin-bottom: 16px;
padding: 16px 24px;
overflow: hidden;
// line-height: 1.5;
word-wrap: break-word;
background: #fff;
border-radius: 2px;
box-shadow: 0 3px 6px -4px rgb(0 0 0 / 12%), 0 6px 16px 0 rgb(0 0 0 / 8%),
0 9px 28px 8px rgb(0 0 0 / 5%);
animation: myfirst 0.2s;
}
@keyframes myfirst {
0% {
right: 0px;
}
25% {
right: 6px;
}
50% {
right: 12px;
}
75% {
right: 18px;
}
100% {
right: 24px;
}
}
.notification-styles {
width: 384px;
height: 116px;
position: absolute;
top: 0px;
right: 20px;
z-index: 10;
margin-bottom: 16px;
padding: 16px 24px;
overflow: hidden;
// line-height: 1.5;
background: #fff;
border-radius: 2px;
box-shadow: 0 4px 12px #00000026;
animation: myfirsts 0.2s;
}
@keyframes myfirsts {
0% {
right: 24px;
}
25% {
right: 18px;
}
50% {
right: 12px;
}
75% {
right: 6px;
}
100% {
right: 0px;
}
}
.title-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.button-content {
display: flex;
justify-content: flex-end;
align-items: center;
.button-style {
display: flex;
justify-content: flex-end;
align-items: center;
height: 26px;
}
}
</style>
其中“告警模拟”按钮是模拟当系统有告警信息时的操作,setInterval是模拟webstockt推送后事件,具有声音的播放暂停功能,并设置有循环播放次数。
public.getStandardTime方法为:
/*
* @Author: zxl 2641337277@qq.com
* @Date: 2022-08-29 11:42:57
* @LastEditors: zxl 2641337277@qq.com
* @LastEditTime: 2022-08-29 13:53:04
* @FilePath: /taizhou-dispatching-command-web/src/utils/timeFun.ts
* @Description1: 1661756385019时间戳转日期字符串
* @Description2: Tue May 15 2018 00:00:00 GMT+0800 (中国标准时间)转日期字符串
* @Description3: 传值为空则获取今日日期字符串
*/
// 传参分三种
// 1.传1661756385019时间戳,转日期字符串
// 2.传Tue May 15 2018 00:00:00 GMT+0800 (中国标准时间),转日期字符串
// 3.传值为空,则获取今日日期字符串
getStandardTime(str) {
var date;
if (Number(str) > 0) {
date = new Date(Number(str));
} else if (str) {
date = new Date(str);
} else {
date = new Date();
}
let y = date.getFullYear()
let M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
let D = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
let h = date.getHours() < 10 ? '0' + date.getHours() : date.getHours()
let m = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()
let s = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
return y + '-' + M + '-' + D + ' ' + h + ':' + m + ':' + s
},
二、引入组件
因告警时系统内告警,所以放在layout里面引入较好。
import Notification from '/@/layouts/default/notification/index.vue';
components: { PageLayout,Notification },
<template>
<div>
<PageLayout />
<Notification></Notification>
</div>
</template>