Skip to content

Commit 6c990bd

Browse files
committed
feat: add urgent notification feature and improve UI components
- Updated index.vue to include an urgent notification button and dialog. - Added UrgentTestDialog.vue component for sending notifications with urgency options. - Enhanced UI elements for better user experience, including improved spacing and layout. - Implemented notification history display with receipt tracking for sent messages. - Added methods for handling notification sending and receipt updates via socket events.
1 parent ca4de54 commit 6c990bd

File tree

3 files changed

+845
-161
lines changed

3 files changed

+845
-161
lines changed

src/components/UrgentNotification.vue

Lines changed: 192 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
>
1414
<v-card-text>
1515
<div class="urgent-title mb-6">
16-
{{ notification?.content?.message || "无内容" }}
16+
{{ currentNotification?.content?.message || "无内容" }}
1717
</div>
1818

1919
<!-- 发送者信息(使用 Vuetify Card) -->
@@ -45,11 +45,47 @@
4545
size="small"
4646
>
4747
<v-icon left size="16"> mdi-clock </v-icon>
48-
{{ formatTime(notification?.timestamp) }}
48+
{{ formatTime(currentNotification?.timestamp) }}
4949
</v-chip>
5050
</v-card-text>
5151
</v-card>
5252

53+
<!-- 多通知导航 -->
54+
<div v-if="hasMultipleNotifications" class="navigation-controls mt-6">
55+
<v-card variant="flat" color="rgba(255,255,255,0.1)">
56+
<v-card-text class="text-center">
57+
<div class="notification-counter mb-3">
58+
<v-chip color="white" variant="flat" size="small">
59+
{{ notificationCountText }}
60+
</v-chip>
61+
</div>
62+
<div class="navigation-buttons">
63+
<v-btn
64+
:disabled="currentIndex === 0"
65+
color="white"
66+
variant="outlined"
67+
size="small"
68+
@click="previousNotification"
69+
>
70+
<v-icon> mdi-chevron-left </v-icon>
71+
上一个
72+
</v-btn>
73+
<v-btn
74+
:disabled="currentIndex === notificationQueue.length - 1"
75+
color="white"
76+
variant="outlined"
77+
size="small"
78+
class="ml-2"
79+
@click="nextNotification"
80+
>
81+
下一个
82+
<v-icon> mdi-chevron-right </v-icon>
83+
</v-btn>
84+
</div>
85+
</v-card-text>
86+
</v-card>
87+
</div>
88+
5389
<!-- 操作按钮 -->
5490
<div class="mt-8">
5591
<v-btn color="white" size="large" variant="flat" @click="close">
@@ -76,14 +112,32 @@ export default {
76112
data() {
77113
return {
78114
visible: false,
79-
notification: null,
115+
notificationQueue: [], // 通知队列
116+
currentIndex: 0, // 当前显示的通知索引
80117
autoCloseTimer: null,
81118
urgentSoundTimer: null,
82119
};
83120
},
84121
computed: {
122+
// 当前显示的通知
123+
currentNotification() {
124+
return this.notificationQueue[this.currentIndex] || null;
125+
},
126+
// 队列中是否有通知
127+
hasNotifications() {
128+
return this.notificationQueue.length > 0;
129+
},
130+
// 是否有多个通知
131+
hasMultipleNotifications() {
132+
return this.notificationQueue.length > 1;
133+
},
134+
// 通知计数文本
135+
notificationCountText() {
136+
if (!this.hasMultipleNotifications) return "";
137+
return `${this.currentIndex + 1} / ${this.notificationQueue.length}`;
138+
},
85139
isUrgent() {
86-
return this.notification?.content?.isUrgent || false;
140+
return this.currentNotification?.content?.isUrgent || false;
87141
},
88142
urgencyColor() {
89143
return this.isUrgent ? "red darken-2" : "blue darken-2";
@@ -101,18 +155,20 @@ export default {
101155
},
102156
senderName() {
103157
const senderInfo =
104-
this.notification?.senderInfo || this.notification?.content?.senderInfo;
158+
this.currentNotification?.senderInfo ||
159+
this.currentNotification?.content?.senderInfo;
105160
if (!senderInfo) return "未知发送者";
106161
107162
return senderInfo.deviceName || senderInfo.deviceType || "未知设备";
108163
},
109164
deviceType() {
110165
const senderInfo =
111-
this.notification?.senderInfo || this.notification?.content?.senderInfo;
166+
this.currentNotification?.senderInfo ||
167+
this.currentNotification?.content?.senderInfo;
112168
return senderInfo?.deviceType || "未知类型";
113169
},
114170
targetDevices() {
115-
return this.notification?.content?.targetDevices || [];
171+
return this.currentNotification?.content?.targetDevices || [];
116172
},
117173
},
118174
beforeUnmount() {
@@ -125,23 +181,39 @@ export default {
125181
},
126182
methods: {
127183
show(notificationData) {
128-
this.notification = notificationData;
129-
this.visible = true;
130-
131-
// 发送显示回执
132-
this.sendDisplayedReceipt();
133-
134-
// 清除之前的自动关闭定时器
135-
if (this.autoCloseTimer) {
136-
clearTimeout(this.autoCloseTimer);
184+
// 检查是否已存在相同的通知(避免重复)
185+
const existingIndex = this.notificationQueue.findIndex(
186+
(n) =>
187+
n.content?.notificationId === notificationData.content?.notificationId
188+
);
189+
190+
if (existingIndex !== -1) {
191+
console.log("通知已存在,跳过添加");
192+
return;
137193
}
138194
139-
// 播放统一的提示音
140-
this.playNotificationSound();
195+
// 添加到队列
196+
this.notificationQueue.push(notificationData);
141197
142-
// 如果是加急通知,启动定时音效
143-
if (this.isUrgent) {
144-
this.startUrgentSound();
198+
// 如果当前没有显示通知,显示第一个
199+
if (!this.visible) {
200+
this.currentIndex = this.notificationQueue.length - 1; // 显示最新的通知
201+
this.visible = true;
202+
this.sendDisplayedReceipt();
203+
this.playNotificationSound();
204+
205+
// 如果是加急通知,启动定时音效
206+
if (this.isUrgent) {
207+
this.startUrgentSound();
208+
}
209+
} else {
210+
// 如果已经有通知在显示,新通知是紧急的话优先显示
211+
if (notificationData.content?.isUrgent && !this.isUrgent) {
212+
this.currentIndex = this.notificationQueue.length - 1;
213+
this.sendDisplayedReceipt();
214+
this.playNotificationSound();
215+
this.startUrgentSound();
216+
}
145217
}
146218
},
147219
close() {
@@ -153,24 +225,58 @@ export default {
153225
console.warn("发送已读回执失败:", error);
154226
}
155227
156-
this.closeWithoutRead();
228+
// 显示已读消息提示,便于设备端重新查看
229+
if (this.currentNotification?.content?.message) {
230+
const notificationType = this.isUrgent ? "紧急通知" : "通知";
231+
if (this.isUrgent) {
232+
this.$message?.error(
233+
notificationType,
234+
`${this.currentNotification.content.message}`
235+
);
236+
} else {
237+
this.$message?.info(
238+
notificationType,
239+
`${this.currentNotification.content.message}`
240+
);
241+
}
242+
}
243+
244+
// 从队列中移除当前通知
245+
if (this.notificationQueue.length > 0) {
246+
this.notificationQueue.splice(this.currentIndex, 1);
247+
248+
// 调整当前索引
249+
if (this.currentIndex >= this.notificationQueue.length) {
250+
this.currentIndex = Math.max(0, this.notificationQueue.length - 1);
251+
}
252+
253+
// 如果还有通知,显示下一个;否则关闭
254+
if (this.notificationQueue.length > 0) {
255+
this.sendDisplayedReceipt();
256+
// 如果新的当前通知是紧急的,启动音效
257+
if (this.isUrgent) {
258+
this.startUrgentSound();
259+
} else {
260+
this.stopUrgentSound();
261+
}
262+
} else {
263+
this.closeWithoutRead();
264+
}
265+
}
157266
},
158267
// 关闭通知但不发送已读回执(用于程序异常或强制关闭)
159268
closeWithoutRead() {
160269
// 立即关闭弹框
161270
this.visible = false;
162-
this.notification = null;
271+
this.notificationQueue = [];
272+
this.currentIndex = 0;
163273
164274
if (this.autoCloseTimer) {
165275
clearTimeout(this.autoCloseTimer);
166276
this.autoCloseTimer = null;
167277
}
168278
169-
// 停止加急音效定时器
170-
if (this.urgentSoundTimer) {
171-
clearInterval(this.urgentSoundTimer);
172-
this.urgentSoundTimer = null;
173-
}
279+
this.stopUrgentSound();
174280
},
175281
formatTime(timestamp) {
176282
if (!timestamp) return "";
@@ -230,12 +336,12 @@ export default {
230336
// 发送显示回执
231337
sendDisplayedReceipt() {
232338
try {
233-
if (this.$refs.eventSender && this.notification?.eventId) {
339+
if (this.$refs.eventSender && this.currentNotification?.eventId) {
234340
this.$refs.eventSender.sendDisplayedReceipt(
235341
{},
236-
this.notification.content.notificationId
342+
this.currentNotification.content.notificationId
237343
);
238-
console.log("已发送显示回执:", this.notification.eventId);
344+
console.log("已发送显示回执:", this.currentNotification.eventId);
239345
}
240346
} catch (error) {
241347
console.warn("发送显示回执失败:", error);
@@ -244,35 +350,65 @@ export default {
244350
// 发送已读回执
245351
sendReadReceipt() {
246352
try {
247-
if (this.$refs.eventSender && this.notification?.eventId) {
353+
if (this.$refs.eventSender && this.currentNotification?.eventId) {
248354
this.$refs.eventSender.sendReadReceipt(
249355
{},
250-
this.notification.content.notificationId
356+
this.currentNotification.content.notificationId
251357
);
252-
console.log("已发送已读回执:", this.notification.eventId);
358+
console.log("已发送已读回执:", this.currentNotification.eventId);
253359
}
254360
} catch (error) {
255361
console.warn("发送已读回执失败:", error);
256362
}
257363
},
364+
// 导航到上一个通知
365+
previousNotification() {
366+
if (this.currentIndex > 0) {
367+
this.currentIndex--;
368+
this.sendDisplayedReceipt();
369+
370+
// 根据新通知的紧急程度调整音效
371+
if (this.isUrgent) {
372+
this.startUrgentSound();
373+
} else {
374+
this.stopUrgentSound();
375+
}
376+
}
377+
},
378+
// 导航到下一个通知
379+
nextNotification() {
380+
if (this.currentIndex < this.notificationQueue.length - 1) {
381+
this.currentIndex++;
382+
this.sendDisplayedReceipt();
383+
384+
// 根据新通知的紧急程度调整音效
385+
if (this.isUrgent) {
386+
this.startUrgentSound();
387+
} else {
388+
this.stopUrgentSound();
389+
}
390+
}
391+
},
258392
// 启动加急通知的定时音效
259393
startUrgentSound() {
260-
// 清除之前的定时器
261-
if (this.urgentSoundTimer) {
262-
clearInterval(this.urgentSoundTimer);
263-
}
394+
this.stopUrgentSound(); // 先清除之前的定时器
264395
265396
// 每秒播放一次提示音
266397
this.urgentSoundTimer = setInterval(() => {
267398
if (this.visible && this.isUrgent) {
268399
this.playNotificationSound();
269400
} else {
270-
// 如果弹框已关闭或不再是加急状态,停止音效
271-
clearInterval(this.urgentSoundTimer);
272-
this.urgentSoundTimer = null;
401+
this.stopUrgentSound();
273402
}
274403
}, 1000);
275404
},
405+
// 停止加急音效
406+
stopUrgentSound() {
407+
if (this.urgentSoundTimer) {
408+
clearInterval(this.urgentSoundTimer);
409+
this.urgentSoundTimer = null;
410+
}
411+
},
276412
},
277413
};
278414
</script>
@@ -341,6 +477,21 @@ export default {
341477
gap: 16px;
342478
}
343479
480+
.navigation-controls {
481+
backdrop-filter: blur(10px);
482+
}
483+
484+
.notification-counter {
485+
color: white;
486+
font-weight: 600;
487+
}
488+
489+
.navigation-buttons {
490+
display: flex;
491+
justify-content: center;
492+
gap: 8px;
493+
}
494+
344495
/* 动画效果 */
345496
@keyframes urgentPulse {
346497
0%,

0 commit comments

Comments
 (0)