diff --git a/resources/js/chat-room.js b/resources/js/chat-room.js index 7c0a1fb..67a412a 100644 --- a/resources/js/chat-room.js +++ b/resources/js/chat-room.js @@ -33,7 +33,7 @@ * - bank-modal.js:处理银行弹窗、转账、排行和标签切换。 * - fishing.js:处理钓鱼抛竿、收竿、浮漂和自动钓鱼循环。 * - fortune-panel.js:提供神秘占卜 fortunePanel Alpine 组件。 - * - profile-controls.js:处理用户资料和资料相关按钮。 + * - profile-controls.js:处理头像选择、个人资料、密码、邮箱验证码和微信绑定入口。 * - shop-controls.js:处理商店弹窗的基础按钮事件。 * - slot-machine.js:提供老虎机 slotPanel/slotFab Alpine 组件。 * - vip-controls.js:处理 VIP 中心弹窗、会员数据渲染、支付跳转和专属进退场设置。 @@ -114,7 +114,24 @@ export { } from "./chat-room/bank-modal.js"; export { bindFishingControls, checkAndAutoStartFishing, createBobber, reelFish, removeBobber, resetFishingBtn, startFishing, stopAutoFishing } from "./chat-room/fishing.js"; export { bindFortunePanelControls, fortunePanel } from "./chat-room/fortune-panel.js"; -export { bindProfileControls } from "./chat-room/profile-controls.js"; +export { + bindProfileControls, + closeAvatarPicker, + closeSettingsModal, + copyWechatBindCode, + generateWechatBindCode, + handleAvatarUpload, + loadHeadfaces, + openAvatarPicker, + openSettingsModal, + saveAvatar, + savePassword, + saveSettings, + selectAvatar, + sendEmailCode, + showInlineMsg, + unbindWechat, +} from "./chat-room/profile-controls.js"; export { bindShopControls } from "./chat-room/shop-controls.js"; export { bindSlotMachineControls, slotFab, slotPanel } from "./chat-room/slot-machine.js"; export { bindVipControls, buyVip, closeVipModal, openVipModal, saveVipPresenceSettings, switchVipTab } from "./chat-room/vip-controls.js"; @@ -214,7 +231,24 @@ import { } from "./chat-room/bank-modal.js"; import { bindFishingControls, checkAndAutoStartFishing, createBobber, reelFish, removeBobber, resetFishingBtn, startFishing, stopAutoFishing } from "./chat-room/fishing.js"; import { bindFortunePanelControls, fortunePanel } from "./chat-room/fortune-panel.js"; -import { bindProfileControls } from "./chat-room/profile-controls.js"; +import { + bindProfileControls, + closeAvatarPicker, + closeSettingsModal, + copyWechatBindCode, + generateWechatBindCode, + handleAvatarUpload, + loadHeadfaces, + openAvatarPicker, + openSettingsModal, + saveAvatar, + savePassword, + saveSettings, + selectAvatar, + sendEmailCode, + showInlineMsg, + unbindWechat, +} from "./chat-room/profile-controls.js"; import { bindShopControls } from "./chat-room/shop-controls.js"; import { bindSlotMachineControls, slotFab, slotPanel } from "./chat-room/slot-machine.js"; import { bindVipControls, buyVip, closeVipModal, openVipModal, saveVipPresenceSettings, switchVipTab } from "./chat-room/vip-controls.js"; @@ -340,6 +374,21 @@ if (typeof window !== "undefined") { fortunePanel, bindMarriageStatusControls, bindProfileControls, + closeAvatarPicker, + closeSettingsModal, + copyWechatBindCode, + generateWechatBindCode, + handleAvatarUpload, + loadHeadfaces, + openAvatarPicker, + openSettingsModal, + saveAvatar, + savePassword, + saveSettings, + selectAvatar, + sendEmailCode, + showInlineMsg, + unbindWechat, bindShopControls, bindSlotMachineControls, slotFab, @@ -448,6 +497,21 @@ if (typeof window !== "undefined") { window.switchBankTab = switchBankTab; window.toggleBankRankSort = toggleBankRankSort; window.applyFontSize = applyFontSize; + window.closeAvatarPicker = closeAvatarPicker; + window.closeSettingsModal = closeSettingsModal; + window.copyWechatBindCode = copyWechatBindCode; + window.generateWechatBindCode = generateWechatBindCode; + window.handleAvatarUpload = handleAvatarUpload; + window.loadHeadfaces = loadHeadfaces; + window.openAvatarPicker = openAvatarPicker; + window.openSettingsModal = openSettingsModal; + window.saveAvatar = saveAvatar; + window.savePassword = savePassword; + window.saveSettings = saveSettings; + window.selectAvatar = selectAvatar; + window.sendEmailCode = sendEmailCode; + window.showInlineMsg = showInlineMsg; + window.unbindWechat = unbindWechat; // 页面加载后立即注册事件委托,具体业务逻辑仍由各子模块负责。 bindChatBanner(); diff --git a/resources/js/chat-room/profile-controls.js b/resources/js/chat-room/profile-controls.js index 5c6f1dd..971eea4 100644 --- a/resources/js/chat-room/profile-controls.js +++ b/resources/js/chat-room/profile-controls.js @@ -1,26 +1,572 @@ -// 头像选择与个人设置弹窗事件绑定,替代 toolbar 中的内联 onclick/onchange。 +// 聊天室头像选择和个人设置模块,负责头像 API、密码修改、邮箱验证码和微信绑定操作。 let profileControlEventsBound = false; +let avatarPickerLoaded = false; /** - * 触发存量全局函数,保持当前头像与设置业务逻辑不变。 + * 读取 CSRF Token。 * - * @param {string} functionName 全局函数名 - * @param {...unknown} args 参数 + * @returns {string} + */ +function csrf() { + return document.querySelector('meta[name="csrf-token"]')?.content || ""; +} + +/** + * 按 ID 获取 DOM 节点。 + * + * @param {string} id + * @returns {HTMLElement|null} + */ +function element(id) { + return document.getElementById(id); +} + +/** + * 显示内联操作结果提示。 + * + * @param {string} elementId + * @param {string} message + * @param {boolean} success * @returns {void} */ -function callGlobal(functionName, ...args) { - // 头像与设置的大段业务仍在 Blade 内,模块阶段先集中桥接旧全局函数。 - if (typeof window[functionName] === "function") { - window[functionName](...args); +export function showInlineMsg(elementId, message, success) { + const target = element(elementId); + if (!target) { + return; + } + + target.style.background = success ? "#f0fdf4" : "#fff5f5"; + target.style.border = success ? "1px solid #86efac" : "1px solid #fecaca"; + target.style.color = success ? "#16a34a" : "#dc2626"; + target.textContent = message; + target.style.display = "block"; + target.style.opacity = "1"; + target.style.transition = "opacity .4s"; + + window.clearTimeout(target._hideTimer); + target._hideTimer = window.setTimeout(() => { + target.style.opacity = "0"; + window.setTimeout(() => { + target.style.display = "none"; + }, 420); + }, 3000); +} + +/** + * 打开头像选择弹窗并懒加载头像列表。 + * + * @returns {void} + */ +export function openAvatarPicker() { + const modal = element("avatar-picker-modal"); + if (!modal) { + return; + } + + modal.style.display = "flex"; + + if (!avatarPickerLoaded) { + void loadHeadfaces(); + avatarPickerLoaded = true; + } +} + +/** + * 关闭头像选择弹窗。 + * + * @returns {void} + */ +export function closeAvatarPicker() { + const modal = element("avatar-picker-modal"); + if (modal) { + modal.style.display = "none"; + } +} + +/** + * 打开个人设置弹窗。 + * + * @returns {void} + */ +export function openSettingsModal() { + const modal = element("settings-modal"); + if (modal) { + modal.style.display = "flex"; + } +} + +/** + * 关闭个人设置弹窗。 + * + * @returns {void} + */ +export function closeSettingsModal() { + const modal = element("settings-modal"); + if (modal) { + modal.style.display = "none"; + } +} + +/** + * 加载系统头像列表。 + * + * @returns {Promise} + */ +export async function loadHeadfaces() { + const grid = element("avatar-grid"); + if (!grid) { + return; + } + + grid.innerHTML = '
加载中...
'; + + try { + const response = await fetch("/headface/list", { + headers: { + Accept: "application/json", + }, + }); + const data = await response.json(); + grid.innerHTML = ""; + + for (const file of data.headfaces || []) { + const image = document.createElement("img"); + image.src = `/images/headface/${file}`; + image.className = "avatar-option"; + image.title = file; + image.dataset.file = file; + image.dataset.avatarFile = file; + image.onerror = () => { + image.style.display = "none"; + }; + grid.appendChild(image); + } + } catch (error) { + grid.innerHTML = '
加载失败
'; + } +} + +/** + * 选中头像并刷新预览。 + * + * @param {string} file + * @param {HTMLElement} imageElement + * @returns {void} + */ +export function selectAvatar(file, imageElement) { + document.querySelectorAll(".avatar-option.selected").forEach((item) => item.classList.remove("selected")); + imageElement.classList.add("selected"); + element("avatar-preview").src = `/images/headface/${file}`; + element("avatar-selected-name").textContent = file; + + const saveButton = element("avatar-save-btn"); + saveButton.disabled = false; + saveButton.dataset.file = file; +} + +/** + * 同步当前用户头像到在线名单。 + * + * @param {string} headface + * @returns {void} + */ +function syncOnlineUserHeadface(headface) { + const username = window.chatContext?.username; + + // 在线名单仍由存量聊天室脚本维护为全局词法变量,这里保留同名访问兼容。 + if (username && typeof onlineUsers !== "undefined" && onlineUsers[username]) { + onlineUsers[username].headface = headface; + } + + if (typeof renderUserList === "function") { + renderUserList(); + } +} + +/** + * 处理本地头像上传。 + * + * @param {HTMLInputElement} input + * @returns {Promise} + */ +export async function handleAvatarUpload(input) { + if (!input.files || !input.files[0]) { + return; + } + + const file = input.files[0]; + if (file.size > 2 * 1024 * 1024) { + window.chatDialog?.alert?.("图片大小不可超过 2MB", "上传失败", "#cc4444"); + input.value = ""; + return; + } + + const button = element("avatar-upload-btn"); + button.disabled = true; + button.textContent = "上传中..."; + + const formData = new FormData(); + formData.append("file", file); + + try { + const response = await fetch("/headface/upload", { + method: "POST", + headers: { + "X-CSRF-TOKEN": csrf(), + "Accept": "application/json", + }, + body: formData, + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + window.chatDialog?.alert?.("自定义头像上传成功!", "提示", "#16a34a"); + const relativeUrl = `/${data.headface}`; + element("avatar-preview").src = relativeUrl; + element("avatar-selected-name").textContent = data.headface; + syncOnlineUserHeadface(data.headface); + document.querySelectorAll(".avatar-option.selected").forEach((item) => item.classList.remove("selected")); + element("avatar-save-btn").disabled = true; + closeAvatarPicker(); + } else { + window.chatDialog?.alert?.(data.message || "上传失败", "操作失败", "#cc4444"); + } + } catch (error) { + window.chatDialog?.alert?.("网络错误,上传失败", "网络异常", "#cc4444"); + } + + button.disabled = false; + button.textContent = "选择本地图片上传"; + input.value = ""; +} + +/** + * 保存当前选中的系统头像。 + * + * @returns {Promise} + */ +export async function saveAvatar() { + const button = element("avatar-save-btn"); + const file = button?.dataset.file || ""; + if (!file) { + return; + } + + button.disabled = true; + button.textContent = "保存中..."; + + try { + const response = await fetch("/headface/change", { + method: "POST", + headers: { + "Content-Type": "application/json", + "X-CSRF-TOKEN": csrf(), + "Accept": "application/json", + }, + body: JSON.stringify({ headface: file }), + }); + const data = await response.json(); + + if (data.status === "success") { + window.chatDialog?.alert?.("头像修改成功!", "提示", "#16a34a"); + syncOnlineUserHeadface(data.headface); + closeAvatarPicker(); + } else { + window.chatDialog?.alert?.(data.message || "修改失败", "操作失败", "#cc4444"); + } + } catch (error) { + window.chatDialog?.alert?.("网络错误", "网络异常", "#cc4444"); + } + + button.disabled = false; + button.textContent = "确定更换"; +} + +/** + * 保存登录密码。 + * + * @returns {Promise} + */ +export async function savePassword() { + const oldPassword = element("set-old-pwd").value; + const newPassword = element("set-new-pwd").value; + const confirmPassword = element("set-new-pwd2").value; + + if (!oldPassword || !newPassword) { + showInlineMsg("pwd-inline-msg", "⚠️ 请填写旧密码和新密码", false); + return; + } + + if (newPassword.length < 6) { + showInlineMsg("pwd-inline-msg", "⚠️ 新密码最少6位!", false); + return; + } + + if (newPassword !== confirmPassword) { + showInlineMsg("pwd-inline-msg", "⚠️ 两次输入的新密码不一致!", false); + return; + } + + try { + const response = await fetch("/user/password", { + method: "PUT", + headers: { + "X-CSRF-TOKEN": csrf(), + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify({ + old_password: oldPassword, + new_password: newPassword, + new_password_confirmation: confirmPassword, + }), + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + showInlineMsg("pwd-inline-msg", "🔒 密码修改成功!", true); + element("set-old-pwd").value = ""; + element("set-new-pwd").value = ""; + element("set-new-pwd2").value = ""; + return; + } + + showInlineMsg("pwd-inline-msg", `❌ ${data.message || "请输入正确的旧密码"}`, false); + } catch (error) { + showInlineMsg("pwd-inline-msg", "🌐 网络异常,请稍后重试", false); + } +} + +/** + * 保存个人资料和密保设置。 + * + * @returns {Promise} + */ +export async function saveSettings() { + const profileData = { + sex: element("set-sex").value, + email: element("set-email").value, + email_code: element("set-email-code")?.value || "", + question: element("set-question").value, + answer: element("set-answer").value, + headface: window.chatContext?.profileHeadface || "1.gif", + sign: window.chatContext?.profileSign || "", + }; + + try { + const response = await fetch("/user/profile", { + method: "PUT", + headers: { + "X-CSRF-TOKEN": csrf(), + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify(profileData), + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + showInlineMsg("settings-inline-msg", "✅ 资料保存成功!", true); + return; + } + + showInlineMsg("settings-inline-msg", `❌ ${data.message || "输入有误"}`, false); + } catch (error) { + showInlineMsg("settings-inline-msg", "🌐 网络异常,请稍后重试", false); + } +} + +/** + * 发送邮箱验证码并启动按钮倒计时。 + * + * @returns {Promise} + */ +export async function sendEmailCode() { + const email = element("set-email").value.trim(); + if (!email) { + window.chatDialog?.alert?.("请先填写邮箱地址后再获取验证码!", "提示", "#d97706"); + return; + } + + const button = element("btn-send-code"); + button.disabled = true; + button.innerText = "正在发送..."; + button.style.opacity = "0.6"; + button.style.cursor = "not-allowed"; + + try { + const response = await fetch("/user/send-email-code", { + method: "POST", + headers: { + "X-CSRF-TOKEN": csrf(), + "Content-Type": "application/json", + "Accept": "application/json", + }, + body: JSON.stringify({ email }), + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + window.chatDialog?.alert?.(data.message || "验证码发送成功,请前往邮箱查收!(有效期5分钟)", "发送成功", "#16a34a"); + startEmailCodeCountdown(button); + return; + } + + window.chatDialog?.alert?.(`发送失败:${data.message || "系统繁忙"}`, "发送失败", "#dc2626"); + resetEmailCodeButton(button); + } catch (error) { + window.chatDialog?.alert?.("网络异常,验证码发送失败,请稍后重试。", "错误", "#6b7280"); + resetEmailCodeButton(button); + } +} + +/** + * 启动邮箱验证码按钮 60 秒倒计时。 + * + * @param {HTMLButtonElement} button + * @returns {void} + */ +function startEmailCodeCountdown(button) { + let remaining = 60; + button.innerText = `${remaining}s 后重试`; + + const timer = window.setInterval(() => { + remaining -= 1; + + if (remaining <= 0) { + window.clearInterval(timer); + resetEmailCodeButton(button); + return; + } + + button.innerText = `${remaining}s 后重试`; + }, 1000); +} + +/** + * 恢复邮箱验证码按钮状态。 + * + * @param {HTMLButtonElement} button + * @returns {void} + */ +function resetEmailCodeButton(button) { + button.innerText = "获取验证码"; + button.disabled = false; + button.style.opacity = "1"; + button.style.cursor = "pointer"; +} + +/** + * 生成微信绑定验证码。 + * + * @returns {Promise} + */ +export async function generateWechatBindCode() { + const button = element("btn-generate-bind-code"); + const input = element("wechat-bind-code"); + const tip = element("bind-code-tip"); + + button.disabled = true; + button.innerText = "生成中..."; + + try { + const response = await fetch("/user/generate-wechat-code", { + method: "POST", + headers: { + "X-CSRF-TOKEN": csrf(), + "Accept": "application/json", + }, + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + input.value = data.code; + tip.style.display = "block"; + element("btn-copy-bind-code").style.display = "inline-block"; + showInlineMsg("settings-inline-msg", "✅ 绑定代码生成成功,请在5分钟内发送给机器人", true); + } else { + showInlineMsg("settings-inline-msg", `❌ 生成失败:${data.message || "未知错误"}`, false); + } + } catch (error) { + showInlineMsg("settings-inline-msg", "🌐 网络异常,请稍后重试", false); + } + + button.disabled = false; + button.innerText = "重新生成"; +} + +/** + * 复制微信绑定验证码。 + * + * @returns {void} + */ +export function copyWechatBindCode() { + const input = element("wechat-bind-code"); + if (!input.value || input.value === "点击生成" || input.value === "生成中...") { + return; + } + + input.select(); + input.setSelectionRange(0, 99999); + + try { + if (navigator.clipboard && window.isSecureContext) { + void navigator.clipboard.writeText(input.value); + } else { + document.execCommand("copy"); + } + + const button = element("btn-copy-bind-code"); + const originalText = button.innerText; + button.innerText = "已复制"; + window.setTimeout(() => { + button.innerText = originalText; + }, 2000); + } catch (error) { + showInlineMsg("settings-inline-msg", "❌ 复制失败,请手动复制", false); + } +} + +/** + * 解除微信绑定。 + * + * @returns {Promise} + */ +export async function unbindWechat() { + const confirmed = typeof window.chatDialog?.confirm === "function" + ? await window.chatDialog.confirm("确定要解除微信绑定吗?解除后将无法接收任何机器人推送通知。", "解除微信绑定") + : window.confirm("确定要解除微信绑定吗?解除后将无法接收任何机器人推送通知。"); + if (!confirmed) { + return; + } + + try { + const response = await fetch("/user/unbind-wechat", { + method: "POST", + headers: { + "X-CSRF-TOKEN": csrf(), + "Accept": "application/json", + }, + }); + const data = await response.json(); + + if (response.ok && data.status === "success") { + window.chatDialog?.alert?.("✅ 解绑成功!请刷新页面获取最新状态。", "提示", "#16a34a"); + window.location.reload(); + return; + } + + window.chatDialog?.alert?.(`❌ 解绑失败:${data.message || "未知错误"}`, "操作失败", "#cc4444"); + } catch (error) { + window.chatDialog?.alert?.("网络异常,解绑失败", "网络异常", "#cc4444"); } } /** * 处理动态头像项选择。 - * 头像列表由 Blade 旧脚本异步生成,Vite 模块只通过 data-avatar-file 接管点击入口。 * - * @param {Element} target 点击目标 + * @param {Element} target * @returns {boolean} */ function handleAvatarOptionClick(target) { @@ -34,17 +580,46 @@ function handleAvatarOptionClick(target) { return false; } - callGlobal("selectAvatar", file, avatarOption); + selectAvatar(file, avatarOption); return true; } +/** + * 挂载头像与设置全局兼容函数。 + * + * @returns {void} + */ +function exposeProfileGlobals() { + window.openAvatarPicker = openAvatarPicker; + window.closeAvatarPicker = closeAvatarPicker; + window.openSettingsModal = openSettingsModal; + window.closeSettingsModal = closeSettingsModal; + window.loadHeadfaces = loadHeadfaces; + window.selectAvatar = selectAvatar; + window.handleAvatarUpload = handleAvatarUpload; + window.saveAvatar = saveAvatar; + window.showInlineMsg = showInlineMsg; + window.savePassword = savePassword; + window.saveSettings = saveSettings; + window.sendEmailCode = sendEmailCode; + window.generateWechatBindCode = generateWechatBindCode; + window.copyWechatBindCode = copyWechatBindCode; + window.unbindWechat = unbindWechat; +} + /** * 绑定头像选择器和个人设置弹窗事件。 * * @returns {void} */ export function bindProfileControls() { + if (typeof window === "undefined") { + return; + } + + exposeProfileGlobals(); + if (profileControlEventsBound || typeof document === "undefined") { return; } @@ -55,10 +630,9 @@ export function bindProfileControls() { return; } - // 头像选择器包含静态按钮和动态头像项,统一用 data-* 事件代理承接。 if (event.target.closest("[data-avatar-picker-close]")) { event.preventDefault(); - callGlobal("closeAvatarPicker"); + closeAvatarPicker(); return; } @@ -69,57 +643,55 @@ export function bindProfileControls() { if (event.target.closest("[data-avatar-save]")) { event.preventDefault(); - callGlobal("saveAvatar"); + void saveAvatar(); return; } if (event.target.closest("[data-avatar-upload-trigger]")) { event.preventDefault(); - // 上传按钮只负责打开隐藏的 file input,上传校验仍由存量 handleAvatarUpload 负责。 - document.getElementById("avatar-upload-input")?.click(); + element("avatar-upload-input")?.click(); return; } if (event.target.closest("[data-settings-modal-close]")) { event.preventDefault(); - callGlobal("closeSettingsModal"); + closeSettingsModal(); return; } - // 设置弹窗的保存、验证码、微信绑定仍走原请求函数,避免迁移中改变接口行为。 if (event.target.closest("[data-settings-save-password]")) { event.preventDefault(); - callGlobal("savePassword"); + void savePassword(); return; } if (event.target.closest("[data-settings-send-email-code]")) { event.preventDefault(); - callGlobal("sendEmailCode"); + void sendEmailCode(); return; } if (event.target.closest("[data-settings-copy-wechat-code]")) { event.preventDefault(); - callGlobal("copyWechatBindCode"); + copyWechatBindCode(); return; } if (event.target.closest("[data-settings-generate-wechat-code]")) { event.preventDefault(); - callGlobal("generateWechatBindCode"); + void generateWechatBindCode(); return; } if (event.target.closest("[data-settings-unbind-wechat]")) { event.preventDefault(); - callGlobal("unbindWechat"); + void unbindWechat(); return; } if (event.target.closest("[data-settings-save-profile]")) { event.preventDefault(); - callGlobal("saveSettings"); + void saveSettings(); return; } @@ -128,9 +700,8 @@ export function bindProfileControls() { return; } - // 只在点击设置弹窗遮罩时关闭,避免内容区点击被误判。 if (event.target.closest("[data-settings-modal-overlay]")) { - callGlobal("closeSettingsModal"); + closeSettingsModal(); } }); @@ -139,7 +710,6 @@ export function bindProfileControls() { return; } - // 保留原上传函数的文件大小校验、接口请求和在线名单刷新逻辑。 - callGlobal("handleAvatarUpload", event.target); + void handleAvatarUpload(event.target); }); } diff --git a/resources/views/chat/frame.blade.php b/resources/views/chat/frame.blade.php index 56c24e2..1ce7c7d 100644 --- a/resources/views/chat/frame.blade.php +++ b/resources/views/chat/frame.blade.php @@ -108,6 +108,8 @@ dailySignInMakeupUrl: @json(\Illuminate\Support\Facades\Route::has('daily-sign-in.makeup') ? route('daily-sign-in.makeup') : null), userJjb: {{ (int) $user->jjb }}, // 当前用户金币(求婚前金额预检查用) myGold: {{ (int) $user->jjb }}, // 赠金币面板显示余额用(赠送成功后前端更新) + profileHeadface: @json(Auth::user()->usersf ?: '1.gif'), + profileSign: @json(Auth::user()->sign ?? ''), chatPreferences: @json($user->chat_preferences ?? []), currentDailyStatus: @json($activeDailyStatus), dailyStatusCatalog: @json($dailyStatusCatalog), diff --git a/resources/views/chat/partials/layout/toolbar.blade.php b/resources/views/chat/partials/layout/toolbar.blade.php index 22937f6..3fee69b 100644 --- a/resources/views/chat/partials/layout/toolbar.blade.php +++ b/resources/views/chat/partials/layout/toolbar.blade.php @@ -235,482 +235,7 @@ {{-- ═══════════ 娱乐游戏大厅弹窗(games/ 子目录)═══════════ --}} @include('chat.partials.games.game-hall') -{{-- ═══════════ 工具条相关 JS 函数 ═══════════ --}} - +{{-- 头像选择和个人设置脚本已迁移到 resources/js/chat-room/profile-controls.js --}} {{-- ═══════════ 商店弹窗 ═══════════ --}}