// 聊天室任命/撤销公告监听,负责渲染大卡片和频道内系统提示。 import { escapeHtml } from "./html.js"; const APPOINTMENT_PHRASES = [ "望再接再厉,大展宏图,为大家服务!", "期待在任期间带领大家更上一层楼!", "众望所归,任重道远,加油!", "新官上任,一展风采,前程似锦!", "相信你能胜任,期待你的精彩表现!", ]; const REVOKE_PHRASES = [ "感谢在任期间的辛勤付出,辛苦了!", "江湖路长,愿前程似锦,未来可期!", "感谢您为大家的奉献,一路顺风!", "在任一场,情谊长存,感谢付出!", "相信以后还有更多精彩,继续加油!", ]; /** * 获取当前聊天消息时间。 * * @returns {string} */ function getChatTimeString() { const now = new Date(); return [ now.getHours().toString().padStart(2, "0"), now.getMinutes().toString().padStart(2, "0"), now.getSeconds().toString().padStart(2, "0"), ].join(":"); } /** * 从候选文案中随机挑选一条公告补充语。 * * @param {string[]} phrases * @returns {string} */ function pickAnnouncementPhrase(phrases) { return phrases[Math.floor(Math.random() * phrases.length)]; } /** * 显示任命或撤销的大卡片公告。 * * @param {object} data * @returns {void} */ export function showAppointmentBanner(data) { if (!window.chatBanner) { return; } const department = data.department_name ? `${escapeHtml(data.department_name)} · ` : ""; const isRevoke = data.type === "revoke"; if (isRevoke) { window.chatBanner.show({ id: "appointment-banner", icon: "📋", title: "职务撤销", name: `${escapeHtml(data.position_icon)} ${escapeHtml(data.target_username)}`, body: `${department}${escapeHtml(data.position_name)} 职务已被撤销`, sub: `由 ${escapeHtml(data.operator_name)} 执行`, gradient: ["#374151", "#4b5563", "#6b7280"], titleColor: "#d1d5db", autoClose: 4500, }); return; } window.chatBanner.show({ id: "appointment-banner", icon: "🎊🎖️🎊", title: "任命公告", name: `${escapeHtml(data.position_icon)} ${escapeHtml(data.target_username)}`, body: `荣任 ${department}${escapeHtml(data.position_name)}`, sub: `由 ${escapeHtml(data.operator_name)} 任命`, gradient: ["#4f46e5", "#7c3aed", "#db2777"], titleColor: "#fde68a", autoClose: 4500, }); } /** * 创建任命/撤销频道内系统消息节点。 * * @param {object} data * @param {boolean} isRevoke * @param {string} department * @param {string} phrase * @param {string} timeString * @returns {HTMLDivElement} */ function createAppointmentMessage(data, isRevoke, department, phrase, timeString) { const message = document.createElement("div"); message.className = "msg-line"; if (isRevoke) { message.style.cssText = "background:#f3f4f6; border-left:3px solid #9ca3af; border-radius:4px; padding:4px 10px; margin:2px 0;"; message.innerHTML = ` 📋 ${escapeHtml(data.target_username)} 的 ${escapeHtml(data.position_icon)} ${department}${escapeHtml(data.position_name)} 职务已被 ${escapeHtml(data.operator_name)} 撤销。${phrase} (${timeString}) `; return message; } message.style.cssText = "background:#f5f3ff; border-left:3px solid #7c3aed; border-radius:4px; padding:4px 10px; margin:2px 0;"; message.innerHTML = ` 🎖️ 恭喜 ${escapeHtml(data.target_username)} 荣任 ${escapeHtml(data.position_icon)} ${department}${escapeHtml(data.position_name)},由 ${escapeHtml(data.operator_name)} 任命。${phrase} (${timeString}) `; return message; } /** * 将系统消息追加到指定聊天窗格并滚动到底部。 * * @param {HTMLElement|null} container * @param {HTMLDivElement} message * @returns {void} */ function appendAppointmentMessage(container, message) { if (!container) { return; } container.appendChild(message); container.scrollTop = container.scrollHeight; } /** * 处理任命/撤销公告事件。 * * @param {CustomEvent} event * @returns {void} */ function handleAppointmentAnnouncement(event) { const data = event.detail || {}; const isRevoke = data.type === "revoke"; const department = data.department_name ? `${escapeHtml(data.department_name)} · ` : ""; // 任命公告才播放礼花,撤销只显示灰色公告卡片。 if (!isRevoke) { window.EffectManager?.play?.("fireworks"); } showAppointmentBanner(data); const phrase = pickAnnouncementPhrase(isRevoke ? REVOKE_PHRASES : APPOINTMENT_PHRASES); const myName = window.chatContext?.username ?? ""; const isInvolved = myName === data.operator_name || myName === data.target_username; const targetContainer = isInvolved ? document.getElementById("chat-messages-container2") : document.getElementById("chat-messages-container"); // 操作者和被操作者写入私聊面板,其余用户写入公屏。 appendAppointmentMessage( targetContainer, createAppointmentMessage(data, isRevoke, department, phrase, getChatTimeString()), ); } /** * 绑定任命/撤销公告浏览器事件。 * * @returns {void} */ export function bindAppointmentAnnouncementControls() { if (typeof window === "undefined") { return; } window.addEventListener("chat:appointment-announced", handleAppointmentAnnouncement); }