diff --git a/app/Http/Controllers/ChatBotController.php b/app/Http/Controllers/ChatBotController.php
index 7e66fcd..0ed03b6 100644
--- a/app/Http/Controllers/ChatBotController.php
+++ b/app/Http/Controllers/ChatBotController.php
@@ -13,8 +13,11 @@
namespace App\Http\Controllers;
+use App\Events\MessageSent;
+use App\Jobs\SaveMessageJob;
use App\Models\Sysparam;
use App\Services\AiChatService;
+use App\Services\ChatStateService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -22,10 +25,11 @@ use Illuminate\Support\Facades\Auth;
class ChatBotController extends Controller
{
/**
- * 构造函数:注入 AI 聊天服务
+ * 构造函数:注入 AI 聊天服务和聊天状态服务
*/
public function __construct(
private readonly AiChatService $aiChat,
+ private readonly ChatStateService $chatState,
) {}
/**
@@ -59,8 +63,40 @@ class ChatBotController extends Controller
$roomId = $request->input('room_id');
try {
+ // 先广播用户的提问消息
+ $userMsg = [
+ 'id' => $this->chatState->nextMessageId($roomId),
+ 'room_id' => $roomId,
+ 'from_user' => $user->username,
+ 'to_user' => 'AI小助手',
+ 'content' => $message,
+ 'is_secret' => false,
+ 'font_color' => '#000000',
+ 'action' => '',
+ 'sent_at' => now()->toDateTimeString(),
+ ];
+ $this->chatState->pushMessage($roomId, $userMsg);
+ broadcast(new MessageSent($roomId, $userMsg));
+ SaveMessageJob::dispatch($userMsg);
+
$result = $this->aiChat->chat($user->id, $message, $roomId);
+ // 广播 AI 回复消息
+ $botMsg = [
+ 'id' => $this->chatState->nextMessageId($roomId),
+ 'room_id' => $roomId,
+ 'from_user' => 'AI小助手',
+ 'to_user' => $user->username,
+ 'content' => $result['reply'],
+ 'is_secret' => false,
+ 'font_color' => '#16a34a',
+ 'action' => '',
+ 'sent_at' => now()->toDateTimeString(),
+ ];
+ $this->chatState->pushMessage($roomId, $botMsg);
+ broadcast(new MessageSent($roomId, $botMsg));
+ SaveMessageJob::dispatch($botMsg);
+
return response()->json([
'status' => 'success',
'reply' => $result['reply'],
diff --git a/resources/views/chat/partials/scripts.blade.php b/resources/views/chat/partials/scripts.blade.php
index 0b89c6d..799ab98 100644
--- a/resources/views/chat/partials/scripts.blade.php
+++ b/resources/views/chat/partials/scripts.blade.php
@@ -264,7 +264,7 @@
const timeStr = msg.sent_at || '';
// 系统用户名列表(不可被选为聊天对象)
- const systemUsers = ['钓鱼播报', '星海小博士', '系统传音', '系统公告'];
+ const systemUsers = ['钓鱼播报', '星海小博士', '系统传音', '系统公告', 'AI小助手'];
// 用户名(单击切换发言对象,双击查看资料;系统用户仅显示文本)
const clickableUser = (uName, color) => {
if (systemUsers.includes(uName)) {
@@ -1011,26 +1011,15 @@
}
chatBotSending = true;
- const now = new Date();
- const timeStr = now.getHours().toString().padStart(2, '0') + ':' +
- now.getMinutes().toString().padStart(2, '0') + ':' +
- now.getSeconds().toString().padStart(2, '0');
-
- // 显示用户发送的消息
- const userDiv = document.createElement('div');
- userDiv.className = 'msg-line';
- userDiv.innerHTML = `${window.chatContext.username}` +
- `对🤖AI小助手说:` +
- `${escapeHtml(content)}` +
- ` (${timeStr})`;
- container2.appendChild(userDiv);
-
// 显示"思考中"提示
+ // 延迟显示"思考中",让广播消息先到达
const thinkDiv = document.createElement('div');
thinkDiv.className = 'msg-line';
thinkDiv.innerHTML = '🤖 AI小助手 正在思考中...';
- container2.appendChild(thinkDiv);
- if (autoScroll) container2.scrollTop = container2.scrollHeight;
+ setTimeout(() => {
+ container2.appendChild(thinkDiv);
+ if (autoScroll) container2.scrollTop = container2.scrollHeight;
+ }, 500);
try {
const res = await fetch(window.chatContext.chatBotUrl, {
@@ -1049,47 +1038,25 @@
const data = await res.json();
- // 移除"思考中"提示
+ // 移除"思考中"提示(消息已通过广播显示)
thinkDiv.remove();
- const replyTime = new Date();
- const replyTimeStr = replyTime.getHours().toString().padStart(2, '0') + ':' +
- replyTime.getMinutes().toString().padStart(2, '0') + ':' +
- replyTime.getSeconds().toString().padStart(2, '0');
-
- if (res.ok && data.status === 'success') {
- // 显示机器人回复
- const botDiv = document.createElement('div');
- botDiv.className = 'msg-line';
- botDiv.style.background = '#f0fdf4';
- botDiv.style.borderLeft = '3px solid #22c55e';
- botDiv.style.padding = '4px 8px';
- botDiv.style.margin = '2px 0';
- botDiv.style.borderRadius = '4px';
- botDiv.innerHTML = `🤖 AI小助手` +
- `对${window.chatContext.username}说:` +
- `${escapeHtml(data.reply)}` +
- ` (${replyTimeStr})` +
- ` [${data.provider}]`;
- container2.appendChild(botDiv);
- } else {
- // 显示错误信息
+ if (!res.ok || data.status !== 'success') {
const errDiv = document.createElement('div');
errDiv.className = 'msg-line';
- errDiv.innerHTML = `🤖【AI小助手】${data.message || '回复失败,请稍后重试'}` +
- ` (${replyTimeStr})`;
- container2.appendChild(errDiv);
+ errDiv.innerHTML = `🤖【AI小助手】${data.message || '回复失败,请稍后重试'}`;
+ container.appendChild(errDiv);
}
} catch (e) {
thinkDiv.remove();
const errDiv = document.createElement('div');
errDiv.className = 'msg-line';
errDiv.innerHTML = '🤖【AI小助手】网络连接错误,请稍后重试';
- container2.appendChild(errDiv);
+ container.appendChild(errDiv);
}
chatBotSending = false;
- if (autoScroll) container2.scrollTop = container2.scrollHeight;
+ scrollToBottom();
}
/**