Files
chatroom/resources/views/chat/partials/toast-notification.blade.php
lkddi 58b63fa8d3 功能:大卡片/小卡片弹出时播放叮咚通知音
effect-sounds.js:
- 新增 ding() 函数:A5(880Hz) + E5(659Hz) 两音叮咚
  每音含基音×2.76铃铛泛音,快冲击+铃铛式衰减
  自动检查 chat_sound_muted 禁音标志
- 导出 ding 至返回对象,底部暴露 window.chatSound = {ding}

toast-notification.blade.php:
- chatToast.show() 中 appendChild 后调用 window.chatSound.ding()

scripts.blade.php:
- chatBanner.show() 开头调用 window.chatSound.ding()
2026-03-01 13:28:19 +08:00

142 lines
5.1 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{--
文件功能:全局右下角 Toast 小卡片通知组件
提供全局 JS API
window.chatToast.show({ title, message, icon?, color?, duration? })
- title: 卡片标题
- message: 卡片内容(支持 HTML
- icon: 左侧 Emoji 图标(可选,默认 💬)
- color: 强调色 HEX可选默认 #336699
- duration: 自动消失毫秒数(可选,默认 60000 = 不自动消失)
- action: { label, onClick } 可选操作按钮
使用示例:
window.chatToast.show({ title: '奖励金币', message: '你收到 100 枚金币!', icon: '🪙', color: '#f59e0b' });
多条 Toast 从右下角向上堆叠,各自独立计时。
@author ChatRoom Laravel
@version 1.0.0
--}}
{{-- Toast 容器(固定右下角,由 JS 动态填充) --}}
<div id="chat-toast-container"
style="position:fixed; bottom:24px; right:24px; z-index:999998;
display:flex; flex-direction:column-reverse; gap:10px; pointer-events:none;">
</div>
<script>
/**
* 全局右下角 Toast 小卡片通知系统。
*
* 可在聊天室任何 JS 代码中调用:
* window.chatToast.show({ title, message, icon, color, duration, action });
*/
window.chatToast = (function() {
const container = document.getElementById('chat-toast-container');
/**
* 显示一条 Toast 通知卡片。
*
* @param {object} opts
* @param {string} opts.title 标题文字
* @param {string} opts.message 内容(支持 HTML
* @param {string} [opts.icon] 左侧 Emoji默认 💬)
* @param {string} [opts.color] 强调色(默认 #336699
* @param {number} [opts.duration] 自动消失毫秒0 表示不自动消失(默认 6000
* @param {object} [opts.action] 操作按钮 { label: string, onClick: function }
*/
function show({
title,
message,
icon = '💬',
color = '#336699',
duration = 6000,
action = null
}) {
const card = document.createElement('div');
card.style.cssText = `
background:#fff; border-radius:10px; overflow:hidden;
box-shadow:0 8px 32px rgba(0,0,0,.18);
min-width:260px; max-width:320px;
font-size:13px; color:#374151; line-height:1.6;
pointer-events:all;
animation:toastSlideIn .3s ease;
opacity:1; transition:opacity .4s;
`;
// 操作按钮 HTML
const actionHtml = action ? `
<div style="margin-top:8px;">
<button class="chat-toast-action-btn"
style="background:${color}; color:#fff; border:none; border-radius:6px;
padding:5px 14px; font-size:12px; font-weight:bold; cursor:pointer;">
${action.label}
</button>
</div>` : '';
card.innerHTML = `
<div style="background:${color}; padding:8px 14px;
display:flex; align-items:center; justify-content:space-between;">
<span style="color:#fff; font-weight:bold; font-size:13px;">
${icon} ${title}
</span>
<button class="chat-toast-close"
style="background:rgba(255,255,255,.25); border:none; color:#fff;
width:22px; height:22px; border-radius:50%; cursor:pointer;
font-size:14px; line-height:22px; text-align:center; padding:0;">×</button>
</div>
<div style="padding:12px 14px 10px;">
<div>${message}</div>
${actionHtml}
</div>
`;
// 关闭按钮
card.querySelector('.chat-toast-close').addEventListener('click', () => dismiss(card));
// 操作按钮
if (action) {
card.querySelector('.chat-toast-action-btn').addEventListener('click', () => {
action.onClick?.();
dismiss(card);
});
}
container.appendChild(card);
// 弹出时播放叮咚通知音
if (window.chatSound) window.chatSound.ding();
// 自动消失
if (duration > 0) {
setTimeout(() => dismiss(card), duration);
}
}
/** 淡出并移除 Toast 卡片 */
function dismiss(card) {
card.style.opacity = '0';
setTimeout(() => card.remove(), 400);
}
return {
show
};
})();
</script>
<style>
@keyframes toastSlideIn {
from {
opacity: 0;
transform: translateX(32px) scale(.96);
}
to {
opacity: 1;
transform: translateX(0) scale(1);
}
}
</style>