diff --git a/frontend-react/src/components/ChatBox.jsx b/frontend-react/src/components/ChatBox.jsx
index e9b7547..6a3196b 100644
--- a/frontend-react/src/components/ChatBox.jsx
+++ b/frontend-react/src/components/ChatBox.jsx
@@ -1,15 +1,116 @@
-import React from 'react';
+import React, { useState, useRef } from 'react';
const ChatBox = () => {
+ const [isHtmlRender, setIsHtmlRender] = useState(false);
+ const [isImageGen, setIsImageGen] = useState(false);
+ const [isDynamicTable, setIsDynamicTable] = useState(false);
+ const [isSettingsExpanded, setIsSettingsExpanded] = useState(false);
+
+ const textareaRef = useRef(null);
+
+ // 自动调整 Textarea 高度
+ const adjustHeight = () => {
+ const textarea = textareaRef.current;
+ if (textarea) {
+ textarea.style.height = 'auto'; // 重置高度以获取正确的 scrollHeight
+ // 重新设置高度,限制最大高度由 CSS max-height 控制
+ textarea.style.height = textarea.scrollHeight + 'px';
+ }
+ };
+
+ const handleInput = () => {
+ adjustHeight();
+ };
+
+ // 生成示例数据
+ const generateMessages = () => {
+ const messages = [];
+ for (let i = 1; i <= 150; i++) {
+ const isUser = i % 2 !== 0;
+ messages.push({
+ id: i,
+ role: isUser ? 'user' : 'ai',
+ content: isUser
+ ? `这是第 ${i} 条用户消息。这是一段比较长的文本,用来测试气泡的换行效果以及滚动条的表现。`
+ : `这是第 ${i} 条 AI 回复。包含 HTML 标签的内容。如果渲染开关开启,这里应该显示粗体字。如果不开启,应该显示原始标签。`
+ });
+ }
+ return messages;
+ };
+
+ const messages = generateMessages();
+
return (
+ {/* 上方:消息列表区域 */}
- {/* 消息列表占位 */}
-
历史消息区域
+
+ {/* 右上角:可折叠设置面板 */}
+
+
setIsSettingsExpanded(!isSettingsExpanded)}
+ >
+ {isSettingsExpanded ? '▼' : '⚙'}
+
+
+ {isSettingsExpanded && (
+
+ )}
+
+
+ {/* 消息列表 */}
+ {messages.map((msg) => (
+
+
+ {isHtmlRender ? (
+
+ ) : (
+
{msg.content}
+ )}
+
+
+ ))}
-
);
diff --git a/frontend-react/src/index.css b/frontend-react/src/index.css
index 44dfdd7..016b561 100644
--- a/frontend-react/src/index.css
+++ b/frontend-react/src/index.css
@@ -18,12 +18,14 @@ html, body, #root {
#root {
display: flex;
flex-direction: column;
- position: relative; /* 关键:让绝对定位的工具栏相对于此容器定位 */
+ position: relative; /* 让绝对定位的工具栏相对于此容器定位 */
+ height: 100%; /* 确保高度占满 */
+ width: 100%;
}
/* --- 顶部工具栏区域 --- */
.toolbar {
- position: absolute; /* 关键:脱离文档流,实现覆盖效果 */
+ position: absolute; /* 脱离文档流,实现覆盖效果 */
top: 0;
left: 0;
right: 0;
@@ -58,16 +60,31 @@ html, body, #root {
display: block; /* 展开时显示 */
}
+/* 工具栏按钮样式微调 */
+.toolbar-toggle-btn {
+ background: none;
+ border: 1px solid #ddd;
+ border-radius: 4px;
+ cursor: pointer;
+ padding: 4px 8px;
+ font-size: 0.8rem;
+ color: #666;
+}
+
/* --- 主内容区域 --- */
.main-container {
- /* 关键布局:占据除工具栏外的所有空间 */
- /* 由于工具栏是 absolute 的,我们需要手动设置 top */
+ /* 占据除工具栏外的所有空间 */
position: absolute;
top: 50px; /* 对应 .toolbar 的默认高度 */
bottom: 0;
left: 0;
right: 0;
+ /* 【关键修复 1】显式设置高度为 100%,而不是 auto */
+ /* 这确保了容器高度由视口决定,而不是由内容撑开 */
+ height: 100%;
+ width: 100%;
+
display: flex;
overflow: hidden; /* 防止主容器本身滚动 */
}
@@ -77,17 +94,21 @@ html, body, #root {
width: 20%;
background-color: #fff;
border-right: 1px solid #ddd;
- overflow-y: auto; /* 独立滚动 */
+ overflow-y: auto; /* 【独立滚动 1】左侧栏滚动 */
height: 100%; /* 填满父容器高度 */
}
+/* --- 中间栏:聊天框 --- */
.chat-area {
flex: 3;
background-color: #fafafa;
+ height: 100%; /* 填满父容器高度 */
+
display: flex;
- flex-direction: column;
- height: 100%;
- overflow: hidden; /* 内部元素滚动,外层不滚动 */
+ flex-direction: column; /* 垂直排列:消息列表 + 输入框 */
+
+ overflow: hidden; /* 禁止外层滚动,强制内部滚动 */
+ position: relative; /* 为绝对定位元素提供参考 */
}
.sidebar-right {
@@ -103,7 +124,7 @@ html, body, #root {
/* 右侧上下分割 */
.right-top, .right-bottom {
flex: 1;
- overflow-y: auto; /* 独立滚动 */
+ overflow-y: auto; /* 【独立滚动 2 & 3】右侧上下部分独立滚动 */
padding: 10px;
min-height: 0; /* 关键:允许 flex 子项收缩 */
}
@@ -111,15 +132,155 @@ html, body, #root {
border-bottom: 1px solid #ddd;
}
-/* 工具栏按钮样式微调 */
-.toolbar-toggle-btn {
- background: none;
+/* --- 消息列表容器 --- */
+.chat-messages {
+ /* 【关键修改 1】不再自动占据剩余空间,高度由内容决定 */
+ flex: 0 0 auto;
+
+ /* 【关键修改 2】设置最大高度,例如视口高度的 80% */
+ max-height: calc(100vh - 110px);
+
+ /* 强制约束高度,防止内容撑开 */
+ min-height: 0;
+
+ /* 内部独立滚动 */
+ overflow-y: auto; /* 内容溢出时显示滚动条 */
+
+ padding: 20px;
+ /* 增加顶部 padding,防止内容被绝对定位的设置面板遮挡 */
+ padding-top: 60px;
+
+ display: flex;
+ flex-direction: column;
+ gap: 15px;
+}
+
+/* --- 设置面板 (右上角) --- */
+.settings-panel {
+ position: absolute;
+ top: 0;
+ right: 0;
+ z-index: 20;
+ background-color: #fff;
+ border-bottom-left-radius: 8px;
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
+ overflow: hidden;
+ transition: all 0.3s ease;
+ max-width: 200px;
+}
+
+.settings-panel.collapsed {
+ width: 40px;
+ height: 40px;
+ cursor: pointer;
+}
+
+.settings-panel.expanded {
+ width: auto;
+ min-width: 150px;
+ padding: 10px;
+ border: 1px solid #eee;
+ border-top: none;
+ border-right: none;
+}
+
+.settings-header {
+ height: 40px;
+ width: 100%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background-color: #f0f0f0;
+ cursor: pointer;
+ font-size: 18px;
+ color: #666;
+}
+
+.settings-panel.collapsed .settings-header:hover {
+ background-color: #e0e0e0;
+}
+
+.settings-options {
+ display: none;
+ flex-direction: column;
+ gap: 10px;
+ padding-top: 10px;
+}
+
+.settings-panel.expanded .settings-options {
+ display: flex;
+}
+
+.setting-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 14px;
+ color: #333;
+}
+
+.setting-item input[type="checkbox"] {
+ margin-right: 8px;
+ cursor: pointer;
+}
+
+/* --- 输入区域容器 --- */
+.chat-input-wrapper {
+ background-color: #fff;
+ border-top: 1px solid #ddd;
+ padding: 10px 20px;
+
+ /* 使用 flex 属性,不伸缩,高度由内容决定 */
+ flex: 0 0 auto;
+
+ /* 保持 flex 布局以便内部对齐 */
+ display: flex;
+ align-items: flex-end; /* 底部对齐,适应多行输入框 */
+ gap: 10px;
+
+ width: 100%;
+}
+
+.chat-input-area {
+ flex: 1; /* 占据除按钮外的所有宽度 */
+ display: flex;
+ /* 移除 height: 100%,让高度由内容决定 */
+}
+
+.chat-input-area textarea {
+ width: 100%;
+ /* 设置初始高度和最大高度 */
+ height: 42px; /* 初始高度 */
+ min-height: 42px; /* 最小高度 */
+ max-height: 300px; /* 最大高度,超过此高度显示滚动条 */
+
+ padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
+ resize: none;
+ outline: none;
+ font-family: inherit;
+ line-height: 1.5;
+ /* 【独立滚动 5】输入框内部滚动 */
+ overflow-y: auto;
+ display: block;
+}
+
+.send-button {
+ height: 42px;
+ padding: 0 20px;
+ background-color: #1890ff;
+ color: white;
+ border: none;
+ border-radius: 4px;
cursor: pointer;
- padding: 4px 8px;
- font-size: 0.8rem;
- color: #666;
+ white-space: nowrap;
+ flex-shrink: 0;
+ margin-bottom: 0; /* 确保与输入框底部对齐 */
+}
+
+.send-button:hover {
+ background-color: #40a9ff;
}
/* 通用滚动条美化 */
@@ -137,3 +298,66 @@ html, body, #root {
::-webkit-scrollbar-thumb:hover {
background: #aaa;
}
+
+/* --- 聊天气泡样式美化 --- */
+
+/* 消息行容器 */
+.message {
+ display: flex;
+ width: 100%;
+ margin-bottom: 10px;
+}
+
+/* 区分左右布局 */
+.message.user {
+ justify-content: flex-end; /* 用户消息靠右 */
+}
+
+.message.ai {
+ justify-content: flex-start; /* AI 消息靠左 */
+}
+
+/* 气泡本体 */
+.message .bubble {
+ max-width: 70%; /* 气泡最大宽度,防止太长 */
+ padding: 10px 15px;
+ border-radius: 12px; /* 圆角 */
+ position: relative;
+ font-size: 14px;
+ line-height: 1.6;
+ word-wrap: break-word; /* 强制换行 */
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); /* 极淡的阴影 */
+}
+
+/* AI 气泡样式 */
+.message.ai .bubble {
+ background-color: #fff;
+ color: #333;
+ border-top-left-radius: 2px; /* 左上角直角或小圆角,增加指向性 */
+ border-bottom-left-radius: 2px;
+ border: 1px solid #eee; /* 极淡的边框 */
+}
+
+/* 用户气泡样式 */
+.message.user .bubble {
+ background-color: #1890ff; /* 亮蓝色 */
+ color: #fff;
+ border-top-right-radius: 2px; /* 右上角直角或小圆角 */
+ border-bottom-right-radius: 2px;
+}
+
+/* 针对 AI 消息中的 HTML 内容进行简单的样式重置 */
+.message.ai .bubble p {
+ margin: 0 0 8px 0;
+}
+.message.ai .bubble p:last-child {
+ margin-bottom: 0;
+}
+.message.ai .bubble ul, .message.ai .bubble ol {
+ margin: 0 0 8px 0;
+ padding-left: 20px;
+}
+.message.ai .bubble b {
+ font-weight: 600;
+ color: #000;
+}