237 lines
5.9 KiB
Vue
237 lines
5.9 KiB
Vue
<template>
|
||
<view v-if="visible" class="notification-wrapper" :class="{ 'slide-in': visible }" :style="{ paddingTop: notificationTop + 'px' }">
|
||
<view class="notification" @click="handleClick">
|
||
<!-- 头像 -->
|
||
<image class="avatar" :src="avatar || 'https://xiaokang88.oss-cn-hangzhou.aliyuncs.com/xk-client-wx/static/xx/ysxx.png'" mode="aspectFill" />
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="content">
|
||
<text class="title">{{ title || '新消息' }}</text>
|
||
<text class="message">{{ displayMessage }}</text>
|
||
</view>
|
||
|
||
<!-- 关闭按钮 -->
|
||
<view class="close" @click.stop="handleClose">
|
||
<text class="close-icon">×</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
export default {
|
||
name: 'MessageNotification',
|
||
data() {
|
||
return {
|
||
visible: false,
|
||
avatar: '',
|
||
title: '',
|
||
message: '',
|
||
roomId: '',
|
||
roomData: null,
|
||
autoHideTimer: null,
|
||
notificationTop: 50 // 默认值
|
||
}
|
||
},
|
||
created() {
|
||
// 获取胶囊按钮位置,计算通知的安全位置
|
||
this.calculateSafeTop();
|
||
},
|
||
computed: {
|
||
displayMessage() {
|
||
// 限制消息长度,超过30个字符显示省略号
|
||
if (this.message && this.message.length > 30) {
|
||
return this.message.substring(0, 30) + '...';
|
||
}
|
||
return this.message || '您有一条新消息';
|
||
}
|
||
},
|
||
mounted() {
|
||
// 监听显示通知事件
|
||
uni.$on('show-message-notification', this.showNotification);
|
||
// 监听隐藏通知事件
|
||
uni.$on('hide-message-notification', this.hideNotification);
|
||
},
|
||
beforeDestroy() {
|
||
// 移除事件监听
|
||
uni.$off('show-message-notification', this.showNotification);
|
||
uni.$off('hide-message-notification', this.hideNotification);
|
||
// 清除定时器
|
||
if (this.autoHideTimer) {
|
||
clearTimeout(this.autoHideTimer);
|
||
}
|
||
},
|
||
methods: {
|
||
/**
|
||
* 计算通知的安全顶部位置(避开胶囊按钮)
|
||
*/
|
||
calculateSafeTop() {
|
||
try {
|
||
// #ifdef MP-WEIXIN
|
||
// 获取胶囊按钮的位置信息
|
||
const menuButtonInfo = wx.getMenuButtonBoundingClientRect();
|
||
// 通知顶部 = 胶囊底部 + 10px 安全边距
|
||
this.notificationTop = menuButtonInfo.bottom + 10;
|
||
// #endif
|
||
|
||
// #ifndef MP-WEIXIN
|
||
// 非微信小程序环境,使用状态栏高度 + 安全边距
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
this.notificationTop = (systemInfo.statusBarHeight || 44) + 10;
|
||
// #endif
|
||
} catch (e) {
|
||
// 获取失败时使用默认值
|
||
this.notificationTop = 50;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 显示通知
|
||
* @param {Object} data 通知数据
|
||
* @param {string} data.avatar 头像
|
||
* @param {string} data.title 标题(发送者昵称)
|
||
* @param {string} data.message 消息内容
|
||
* @param {string} data.roomId 房间ID
|
||
* @param {Object} data.roomData 房间数据(用于跳转)
|
||
*/
|
||
showNotification(data) {
|
||
// 清除之前的定时器
|
||
if (this.autoHideTimer) {
|
||
clearTimeout(this.autoHideTimer);
|
||
}
|
||
|
||
// 设置通知数据
|
||
this.avatar = data.avatar || '';
|
||
this.title = data.title || '新消息';
|
||
this.message = data.message || '您有一条新消息';
|
||
this.roomId = data.roomId || '';
|
||
this.roomData = data.roomData || null;
|
||
|
||
// 显示通知
|
||
this.visible = true;
|
||
|
||
// 3秒后自动隐藏
|
||
this.autoHideTimer = setTimeout(() => {
|
||
this.hideNotification();
|
||
}, 3000);
|
||
},
|
||
|
||
/**
|
||
* 隐藏通知
|
||
*/
|
||
hideNotification() {
|
||
this.visible = false;
|
||
if (this.autoHideTimer) {
|
||
clearTimeout(this.autoHideTimer);
|
||
this.autoHideTimer = null;
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 点击通知,跳转到聊天页面
|
||
*/
|
||
handleClick() {
|
||
this.hideNotification();
|
||
|
||
if (this.roomId && this.roomData) {
|
||
uni.navigateTo({
|
||
url: `/subPackages/chat/chat?room_id=${this.roomId}&nick_name=${this.roomData.nick_name || ''}&user_id=${this.roomData.user_id || ''}&avatar=${encodeURIComponent(this.roomData.avatar || '')}`
|
||
});
|
||
} else if (this.roomId) {
|
||
// 如果只有 roomId,也尝试跳转
|
||
uni.navigateTo({
|
||
url: `/subPackages/chat/chat?room_id=${this.roomId}`
|
||
});
|
||
}
|
||
},
|
||
|
||
/**
|
||
* 关闭通知
|
||
*/
|
||
handleClose() {
|
||
this.hideNotification();
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.notification-wrapper {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 9999;
|
||
padding-left: 20rpx;
|
||
padding-right: 20rpx;
|
||
padding-bottom: 20rpx;
|
||
// padding-top 通过 :style 动态设置,避开胶囊按钮
|
||
transform: translateY(-100%);
|
||
transition: transform 0.3s ease-out;
|
||
|
||
&.slide-in {
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
.notification {
|
||
display: flex;
|
||
align-items: center;
|
||
background: #ffffff;
|
||
border-radius: 20rpx;
|
||
padding: 24rpx;
|
||
box-shadow: 0 8rpx 30rpx rgba(0, 0, 0, 0.15);
|
||
|
||
.avatar {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
background-color: #f5f5f5;
|
||
}
|
||
|
||
.content {
|
||
flex: 1;
|
||
margin-left: 20rpx;
|
||
overflow: hidden;
|
||
|
||
.title {
|
||
display: block;
|
||
font-size: 30rpx;
|
||
font-weight: 600;
|
||
color: #333333;
|
||
margin-bottom: 8rpx;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.message {
|
||
display: block;
|
||
font-size: 26rpx;
|
||
color: #666666;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
white-space: nowrap;
|
||
}
|
||
}
|
||
|
||
.close {
|
||
flex-shrink: 0;
|
||
width: 48rpx;
|
||
height: 48rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-left: 16rpx;
|
||
|
||
.close-icon {
|
||
font-size: 40rpx;
|
||
color: #999999;
|
||
line-height: 1;
|
||
}
|
||
}
|
||
}
|
||
</style>
|
||
|