diff --git a/resources/js/chat-room.js b/resources/js/chat-room.js
index a94ffa3..e14d5d0 100644
--- a/resources/js/chat-room.js
+++ b/resources/js/chat-room.js
@@ -4,6 +4,7 @@
export { escapeHtml, escapeHtmlWithLineBreaks } from "./chat-room/html.js";
export { bindAppointmentAnnouncementControls, showAppointmentBanner } from "./chat-room/appointment-announcement.js";
export { bindChatBanner } from "./chat-room/banner.js";
+export { bindChatBotControls, clearChatBotContext, sendToChatBot } from "./chat-room/chat-bot.js";
export { bindGlobalDialogControls } from "./chat-room/dialog.js";
export { bindDailySignInControls } from "./chat-room/daily-sign-in.js";
export { applyFontSize, bindChatFontSizeControl, CHAT_FONT_SIZE_STORAGE_KEY, restoreChatFontSize } from "./chat-room/font-size.js";
@@ -83,6 +84,7 @@ export { createMessageQueue } from "./chat-room/message-queue.js";
import { escapeHtml, escapeHtmlWithLineBreaks } from "./chat-room/html.js";
import { bindAppointmentAnnouncementControls, showAppointmentBanner } from "./chat-room/appointment-announcement.js";
import { bindChatBanner } from "./chat-room/banner.js";
+import { bindChatBotControls, clearChatBotContext, sendToChatBot } from "./chat-room/chat-bot.js";
import { bindGlobalDialogControls } from "./chat-room/dialog.js";
import { bindDailySignInControls } from "./chat-room/daily-sign-in.js";
import { applyFontSize, bindChatFontSizeControl, CHAT_FONT_SIZE_STORAGE_KEY, restoreChatFontSize } from "./chat-room/font-size.js";
@@ -167,6 +169,9 @@ if (typeof window !== "undefined") {
bindAppointmentAnnouncementControls,
showAppointmentBanner,
bindChatBanner,
+ bindChatBotControls,
+ clearChatBotContext,
+ sendToChatBot,
bindGlobalDialogControls,
bindDailySignInControls,
applyFontSize,
@@ -265,6 +270,8 @@ if (typeof window !== "undefined") {
window.scheduleRenderMobileUserList = scheduleRenderMobileUserList;
window.switchMobileTab = switchMobileTab;
window.switchTarget = switchTarget;
+ window.clearChatBotContext = clearChatBotContext;
+ window.sendToChatBot = sendToChatBot;
window.runFeatureShortcut = runFeatureShortcut;
window.runToolbarAction = runToolbarAction;
window.openHolidayRunFromSystemMessage = openHolidayRunFromSystemMessage;
@@ -284,6 +291,7 @@ if (typeof window !== "undefined") {
// 页面加载后立即注册事件委托,具体业务逻辑仍由各子模块负责。
bindChatBanner();
+ bindChatBotControls();
bindAppointmentAnnouncementControls();
bindGlobalDialogControls();
bindDailySignInControls();
diff --git a/resources/js/chat-room/chat-bot.js b/resources/js/chat-room/chat-bot.js
new file mode 100644
index 0000000..94eedf1
--- /dev/null
+++ b/resources/js/chat-room/chat-bot.js
@@ -0,0 +1,134 @@
+// 聊天室 AI 小班长交互模块,提供 sendToChatBot/clearChatBotContext 兼容入口。
+
+import { escapeHtml } from "./html.js";
+
+let chatBotSending = false;
+
+/**
+ * 读取页面 CSRF Token。
+ *
+ * @returns {string}
+ */
+function getCsrfToken() {
+ return document.querySelector('meta[name="csrf-token"]')?.getAttribute("content") || "";
+}
+
+/**
+ * 判断包厢窗口是否需要自动滚动到底部。
+ *
+ * @returns {boolean}
+ */
+function shouldAutoScroll() {
+ return window.isChatAutoScrollEnabled?.() ?? true;
+}
+
+/**
+ * 将系统提示追加到包厢窗口。
+ *
+ * @param {string} html
+ * @returns {void}
+ */
+function appendPrivateSystemLine(html) {
+ const messageBox = document.getElementById("chat-messages-container2");
+ if (!messageBox) {
+ return;
+ }
+
+ const line = document.createElement("div");
+ line.className = "msg-line";
+ line.innerHTML = html;
+ messageBox.appendChild(line);
+
+ if (shouldAutoScroll()) {
+ messageBox.scrollTop = messageBox.scrollHeight;
+ }
+}
+
+/**
+ * 将 AI 错误提示追加到包厢窗口。
+ *
+ * @param {string} text
+ * @returns {void}
+ */
+function appendBotError(text) {
+ appendPrivateSystemLine(`🤖【AI小班长】${escapeHtml(text)}`);
+}
+
+/**
+ * 发送消息给 AI 机器人。
+ *
+ * @param {string} content
+ * @param {boolean} [isSecret]
+ * @returns {Promise}
+ */
+export async function sendToChatBot(content, isSecret = false) {
+ if (chatBotSending) {
+ window.chatDialog?.alert?.("AI 正在思考中,请稍候...", "提示", "#336699");
+ return;
+ }
+
+ chatBotSending = true;
+
+ try {
+ const response = await fetch(window.chatContext.chatBotUrl, {
+ method: "POST",
+ headers: {
+ "X-CSRF-TOKEN": getCsrfToken(),
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ },
+ body: JSON.stringify({
+ message: content,
+ room_id: window.chatContext.roomId,
+ is_secret: isSecret ? 1 : 0,
+ }),
+ });
+
+ const data = await response.json();
+
+ if (!response.ok || data.status !== "success") {
+ // AI 接口错误只写入包厢窗口,避免失败提示刷到公屏。
+ appendBotError(data.message || "回复失败,请稍后重试");
+ }
+ } catch (error) {
+ appendBotError("网络连接错误,请稍后重试");
+ } finally {
+ chatBotSending = false;
+ }
+}
+
+/**
+ * 清除与 AI 小助手的对话上下文。
+ *
+ * @returns {Promise}
+ */
+export async function clearChatBotContext() {
+ try {
+ const response = await fetch(window.chatContext.chatBotClearUrl, {
+ method: "POST",
+ headers: {
+ "X-CSRF-TOKEN": getCsrfToken(),
+ "Accept": "application/json",
+ },
+ });
+ const data = await response.json();
+
+ appendPrivateSystemLine(`🤖【系统】${escapeHtml(data.message || "对话已重置")}`);
+ } catch (error) {
+ window.chatDialog?.alert?.(`清除失败:${error.message}`, "操作失败", "#cc4444");
+ }
+}
+
+/**
+ * 暴露 AI 小班长操作给存量发送消息逻辑。
+ *
+ * @returns {void}
+ */
+export function bindChatBotControls() {
+ if (typeof window === "undefined") {
+ return;
+ }
+
+ window.sendToChatBot = sendToChatBot;
+ window.clearChatBotContext = clearChatBotContext;
+}
diff --git a/resources/views/chat/partials/ai-chatbot.blade.php b/resources/views/chat/partials/ai-chatbot.blade.php
index 7955e0d..6816900 100644
--- a/resources/views/chat/partials/ai-chatbot.blade.php
+++ b/resources/views/chat/partials/ai-chatbot.blade.php
@@ -1,87 +1,6 @@
-
+ sendToChatBot 与 clearChatBotContext 已迁移到 resources/js/chat-room/chat-bot.js,
+ 由 resources/js/chat-room.js 统一通过 Vite 加载并暴露兼容全局函数。
+--}}
diff --git a/resources/views/chat/partials/scripts.blade.php b/resources/views/chat/partials/scripts.blade.php
index 867689b..ecfd02c 100644
--- a/resources/views/chat/partials/scripts.blade.php
+++ b/resources/views/chat/partials/scripts.blade.php
@@ -47,6 +47,8 @@
// 暂时暴露给已迁移的手机抽屉 Vite 模块读取,后续在线名单整体迁移后可移除。
window.onlineUsers = onlineUsers;
let autoScroll = true;
+ // 给已迁移到 Vite 的模块只读判断自动滚动状态,避免直接依赖 Blade 脚本作用域。
+ window.isChatAutoScrollEnabled = () => autoScroll;
let userBadgeRotationTick = 0;
let userListRenderTimer = null;
let _maxMsgId = 0; // 记录当前收到的最大消息 ID