修补选中聊天不更换角色bug
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import Toolbar from './components/ToolBar/ToolBar';
|
||||
import ChatBox from './components/ChatBox/ChatBox';
|
||||
import DicePanel from './components/DicePanel/DicePanel';
|
||||
@@ -7,25 +7,9 @@ import PresetPanel from './components/PresetPanel/PresetPanel';
|
||||
import './index.css';
|
||||
|
||||
function App() {
|
||||
const [selectedRole, setSelectedRole] = useState(null);
|
||||
const [selectedChat, setSelectedChat] = useState(null);
|
||||
|
||||
const handleRoleChange = (role) => {
|
||||
setSelectedRole(role);
|
||||
console.log('角色已更改:', role);
|
||||
};
|
||||
|
||||
const handleChatChange = (role, chat) => {
|
||||
setSelectedChat(chat);
|
||||
console.log('聊天已更改:', role, chat);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<Toolbar
|
||||
onRoleChange={handleRoleChange}
|
||||
onChatChange={handleChatChange}
|
||||
/>
|
||||
<Toolbar />
|
||||
|
||||
{/* 主内容容器 */}
|
||||
<div className="main-container">
|
||||
@@ -36,10 +20,7 @@ function App() {
|
||||
|
||||
{/* 中间栏:聊天框 */}
|
||||
<div className="chat-area">
|
||||
<ChatBox
|
||||
selectedRole={selectedRole}
|
||||
selectedChat={selectedChat}
|
||||
/>
|
||||
<ChatBox />
|
||||
</div>
|
||||
|
||||
{/* 右侧栏 */}
|
||||
|
||||
95
frontend-react/src/Store/Slices/ChatBoxSlice.jsx
Normal file
95
frontend-react/src/Store/Slices/ChatBoxSlice.jsx
Normal file
@@ -0,0 +1,95 @@
|
||||
import { create } from 'zustand';
|
||||
import { subscribeWithSelector } from 'zustand/middleware';
|
||||
|
||||
const useChatBoxStore = create(
|
||||
subscribeWithSelector((set, get) => ({
|
||||
// 聊天历史消息列表
|
||||
messages: [],
|
||||
|
||||
// 用户名称
|
||||
userName: '',
|
||||
|
||||
// 角色名称
|
||||
characterName: '',
|
||||
|
||||
// 当前选中的角色
|
||||
currentRole: null,
|
||||
|
||||
// 当前选中的聊天
|
||||
currentChat: null,
|
||||
|
||||
// 是否正在加载
|
||||
isLoading: false,
|
||||
|
||||
// 错误信息
|
||||
error: null,
|
||||
|
||||
// 设置消息列表
|
||||
setMessages: (messages) => set({ messages }),
|
||||
|
||||
// 设置用户名称
|
||||
setUserName: (userName) => set({ userName }),
|
||||
|
||||
// 设置角色名称
|
||||
setCharacterName: (characterName) => set({ characterName }),
|
||||
|
||||
// 设置当前角色
|
||||
setCurrentRole: (role) => set({ currentRole: role }),
|
||||
|
||||
// 设置当前聊天
|
||||
setCurrentChat: (chat) => set({ currentChat: chat }),
|
||||
|
||||
// 加载聊天历史
|
||||
fetchChatHistory: async (roleName, chatName) => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
const response = await fetch(`/api/chat_box/get_chat_history?role_name=${encodeURIComponent(roleName)}&chat_name=${encodeURIComponent(chatName)}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch chat history');
|
||||
}
|
||||
const data = await response.json();
|
||||
set({
|
||||
messages: data.messages || [],
|
||||
userName: data.userName || 'User',
|
||||
characterName: data.characterName || 'Assistant',
|
||||
isLoading: false
|
||||
});
|
||||
} catch (error) {
|
||||
set({
|
||||
error: error.message,
|
||||
isLoading: false
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 清空聊天历史
|
||||
clearChatHistory: () => set({
|
||||
messages: [],
|
||||
userName: '',
|
||||
characterName: '',
|
||||
error: null
|
||||
}),
|
||||
|
||||
// 更新特定消息的内容
|
||||
updateMessage: (id, content) => set((state) => ({
|
||||
messages: state.messages.map((msg) =>
|
||||
msg.id === id ? { ...msg, content } : msg
|
||||
)
|
||||
})),
|
||||
}))
|
||||
);
|
||||
|
||||
// 监听角色和聊天变化,自动加载聊天历史
|
||||
useChatBoxStore.subscribe(
|
||||
(state) => ({ role: state.currentRole, chat: state.currentChat }),
|
||||
({ role, chat }) => {
|
||||
if (role && chat) {
|
||||
useChatBoxStore.getState().fetchChatHistory(role, chat);
|
||||
} else {
|
||||
useChatBoxStore.getState().clearChatHistory();
|
||||
}
|
||||
},
|
||||
{ equalityFn: (a, b) => a.role === b.role && a.chat === b.chat }
|
||||
);
|
||||
|
||||
export default useChatBoxStore;
|
||||
@@ -403,3 +403,27 @@
|
||||
.send-button:hover {
|
||||
background-color: #40a9ff;
|
||||
}
|
||||
|
||||
/* 加载状态样式 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* 错误信息样式 */
|
||||
.error {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
color: #f5222d;
|
||||
font-size: 14px;
|
||||
background-color: rgba(245, 34, 45, 0.05);
|
||||
border-radius: 4px;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React, { useState, useRef } from 'react';
|
||||
import useChatBoxStore from '../../Store/Slices/ChatBoxSlice';
|
||||
import './ChatBox.css';
|
||||
|
||||
const ChatBox = ({ selectedRole, selectedChat }) => {
|
||||
const ChatBox = () => {
|
||||
const [isHtmlRender, setIsHtmlRender] = useState(false);
|
||||
const [isImageGen, setIsImageGen] = useState(false);
|
||||
const [isDynamicTable, setIsDynamicTable] = useState(false);
|
||||
@@ -10,6 +11,9 @@ const ChatBox = ({ selectedRole, selectedChat }) => {
|
||||
|
||||
const textareaRef = useRef(null);
|
||||
|
||||
// 从 store 获取状态
|
||||
const { messages, userName, characterName, isLoading, error } = useChatBoxStore();
|
||||
|
||||
// 自动调整 Textarea 高度
|
||||
const adjustHeight = () => {
|
||||
const textarea = textareaRef.current;
|
||||
@@ -60,36 +64,21 @@ const ChatBox = ({ selectedRole, selectedChat }) => {
|
||||
setEditContent('');
|
||||
};
|
||||
|
||||
// 生成示例数据
|
||||
const generateMessages = () => {
|
||||
const messages = [];
|
||||
for (let i = 1; i <= 150; i++) {
|
||||
const isUser = i % 2 !== 0;
|
||||
messages.push({
|
||||
id: i,
|
||||
role: isUser ? 'user' : 'ai',
|
||||
name: isUser ? '我' : 'AI助手',
|
||||
content: isUser
|
||||
? `这是第 ${i} 条用户消息。这是一段比较长的文本,用来测试气泡的换行效果以及滚动条的表现。`
|
||||
: `这是第 ${i} 条 AI 回复。<b>包含 HTML 标签</b>的内容。如果渲染开关开启,这里应该显示粗体字。如果不开启,应该显示原始标签。`
|
||||
});
|
||||
}
|
||||
return messages;
|
||||
};
|
||||
|
||||
const messages = generateMessages();
|
||||
|
||||
return (
|
||||
<div className="chat-box">
|
||||
{/* 上方:消息列表区域 */}
|
||||
<div className="chat-messages">
|
||||
{/* 加载状态和错误信息 */}
|
||||
{isLoading && <div className="loading">加载中...</div>}
|
||||
{error && <div className="error">{error}</div>}
|
||||
|
||||
{/* 消息列表 */}
|
||||
{messages.map((msg) => (
|
||||
<div key={msg.id} className={`message ${msg.role}`}>
|
||||
<div className="message-container">
|
||||
{/* 消息名称和工具栏在同一行 */}
|
||||
<div className="message-header">
|
||||
<div className="message-name">{msg.name}</div>
|
||||
<div className="message-name">{msg.role === 'user' ? userName : characterName}</div>
|
||||
|
||||
{/* 消息工具栏 */}
|
||||
<div className="message-toolbar">
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import useRoleSelectorStore from '../../store/Slices/RoleSelectorSlice';
|
||||
import useChatBoxStore from '../../Store/Slices/ChatBoxSlice';
|
||||
import './RoleSelector.css';
|
||||
|
||||
const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
const RoleSelector = () => {
|
||||
const panelRef = useRef(null);
|
||||
|
||||
// 从 Zustand store 中获取状态和操作
|
||||
@@ -37,6 +38,9 @@ const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
resetPanel
|
||||
} = useRoleSelectorStore();
|
||||
|
||||
// 从 ChatBoxStore 获取状态更新方法
|
||||
const { setCurrentRole, setCurrentChat } = useChatBoxStore();
|
||||
|
||||
// 组件挂载时获取数据
|
||||
useEffect(() => {
|
||||
fetchRoleData();
|
||||
@@ -59,41 +63,56 @@ const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
// 处理角色选择
|
||||
const handleRoleSelect = (role) => {
|
||||
setSelectedRole(role);
|
||||
if (onRoleChange) {
|
||||
onRoleChange(role);
|
||||
}
|
||||
// 更新 ChatBoxStore 中的当前角色
|
||||
setCurrentRole(role);
|
||||
|
||||
// 如果该角色有聊天记录,默认选择第一个
|
||||
if (roleData[role] && roleData[role].length > 0) {
|
||||
const firstChat = roleData[role][0];
|
||||
setSelectedChat(firstChat);
|
||||
if (onChatChange) {
|
||||
onChatChange(role, firstChat);
|
||||
}
|
||||
// 更新 ChatBoxStore 中的当前聊天
|
||||
setCurrentChat(firstChat);
|
||||
} else {
|
||||
setSelectedChat(null);
|
||||
// 清除 ChatBoxStore 中的当前聊天
|
||||
setCurrentChat(null);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理聊天选择
|
||||
const handleChatSelect = (chat) => {
|
||||
setSelectedChat(chat);
|
||||
setHoveredRole(null);
|
||||
setClickedRole(null);
|
||||
if (onChatChange) {
|
||||
onChatChange(selectedRole, chat);
|
||||
}
|
||||
// 获取当前展开的角色(聊天所属的角色)
|
||||
const currentRole = hoveredRole || clickedRole;
|
||||
|
||||
setSelectedChat(chat);
|
||||
setSelectedRole(currentRole); // 使用当前展开的角色
|
||||
setHoveredRole(null);
|
||||
setClickedRole(null);
|
||||
// 更新 ChatBoxStore 中的当前聊天和角色
|
||||
setCurrentChat(chat);
|
||||
setCurrentRole(currentRole);
|
||||
};
|
||||
|
||||
// 处理角色卡片点击
|
||||
const handleRoleCardClick = (role) => {
|
||||
if (clickedRole === role) {
|
||||
setClickedRole(null);
|
||||
} else {
|
||||
setClickedRole(role);
|
||||
handleRoleSelect(role);
|
||||
}
|
||||
};
|
||||
const handleRoleCardClick = (role) => {
|
||||
if (clickedRole === role) {
|
||||
setClickedRole(null);
|
||||
// 取消选择角色时,更新 selectedRole 和 selectedChat
|
||||
setSelectedRole(null);
|
||||
setSelectedChat(null);
|
||||
// 同步更新 ChatBoxStore 中的状态
|
||||
setCurrentRole(null);
|
||||
setCurrentChat(null);
|
||||
} else {
|
||||
setClickedRole(role);
|
||||
handleRoleSelect(role);
|
||||
setSelectedRole(role);
|
||||
setSelectedChat(chat);
|
||||
// 同步更新 ChatBoxStore 中的状态
|
||||
setSele
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 处理搜索
|
||||
const handleSearchChange = (e) => {
|
||||
@@ -112,9 +131,8 @@ const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
const newName = e.target.value;
|
||||
handleRenameRole(oldName, newName);
|
||||
if (selectedRole === oldName && newName && newName !== oldName) {
|
||||
if (onRoleChange) {
|
||||
onRoleChange(newName);
|
||||
}
|
||||
// 更新 ChatBoxStore 中的当前角色
|
||||
setCurrentRole(newName);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -130,9 +148,8 @@ const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
const newName = e.target.value;
|
||||
handleRenameChat(oldName, newName);
|
||||
if (selectedChat === oldName && newName && newName !== oldName) {
|
||||
if (onChatChange) {
|
||||
onChatChange(selectedRole, newName);
|
||||
}
|
||||
// 更新 ChatBoxStore 中的当前聊天
|
||||
setCurrentChat(selectedRole, newName);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -147,13 +164,12 @@ const RoleSelector = ({ onRoleChange, onChatChange }) => {
|
||||
const confirmDeleteWrapper = () => {
|
||||
confirmDelete();
|
||||
if (deleteType === 'role' && selectedRole === showDeleteConfirm) {
|
||||
if (onRoleChange) {
|
||||
onRoleChange(null);
|
||||
}
|
||||
// 清除 ChatBoxStore 中的当前角色和聊天
|
||||
setCurrentRole(null);
|
||||
setCurrentChat(null);
|
||||
} else if (deleteType === 'chat' && selectedChat === showDeleteConfirm) {
|
||||
if (onChatChange) {
|
||||
onChatChange(selectedRole, null);
|
||||
}
|
||||
// 清除 ChatBoxStore 中的当前聊天
|
||||
setCurrentChat(null);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user