读取本地chatandrole完成并优化排列
This commit is contained in:
0
data/chat/test/12312.jsonl
Normal file
0
data/chat/test/12312.jsonl
Normal file
@@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import Toolbar from './components/Toolbar/Toolbar';
|
||||
import Toolbar from './components/ToolBar/ToolBar';
|
||||
import ChatBox from './components/ChatBox/ChatBox';
|
||||
import DicePanel from './components/DicePanel/DicePanel';
|
||||
import ImageDisplay from './components/ImageDisplay/ImageDisplay';
|
||||
@@ -7,7 +7,6 @@ import PresetPanel from './components/PresetPanel/PresetPanel';
|
||||
import './index.css';
|
||||
|
||||
function App() {
|
||||
const [isToolbarExpanded, setIsToolbarExpanded] = useState(false);
|
||||
const [selectedRole, setSelectedRole] = useState(null);
|
||||
const [selectedChat, setSelectedChat] = useState(null);
|
||||
|
||||
@@ -24,11 +23,8 @@ function App() {
|
||||
return (
|
||||
<div className="app">
|
||||
<Toolbar
|
||||
isExpanded={isToolbarExpanded}
|
||||
onToggle={() => setIsToolbarExpanded(!isToolbarExpanded)}
|
||||
onRoleChange={handleRoleChange}
|
||||
onChatChange={handleChatChange}
|
||||
selectedRole={selectedRole}
|
||||
/>
|
||||
|
||||
{/* 主内容容器 */}
|
||||
|
||||
@@ -2,18 +2,19 @@
|
||||
|
||||
/* React 组件根容器 */
|
||||
.chat-box {
|
||||
height: 95%;
|
||||
height: 100%; /* 修改为100%,填满父容器 */
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #fafafa;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
}
|
||||
|
||||
/* 消息列表容器 */
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
max-height: 100%;
|
||||
max-height: calc(95vh - 62px); /* 减去输入区域的高度 */
|
||||
overflow-y: auto;
|
||||
padding: 20px;
|
||||
padding-top: 60px;
|
||||
@@ -147,7 +148,7 @@
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 消息工具栏 */
|
||||
/* 消息工具栏 - 优化布局使图标更紧凑 */
|
||||
.message-toolbar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -172,7 +173,7 @@
|
||||
|
||||
.toolbar-buttons {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
gap: 3px; /* 减少图标之间的间距 */
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
@@ -355,13 +356,17 @@
|
||||
background-color: #fff;
|
||||
border-top: 1px solid #ddd;
|
||||
padding: 10px 20px;
|
||||
flex: 0 0 auto;
|
||||
height: 62px; /* 明确设置高度 */
|
||||
flex-shrink: 0; /* 防止被压缩 */
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
|
||||
.chat-input-area {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
@@ -1,80 +1,69 @@
|
||||
/* ==================== 顶部工具栏区域 ==================== */
|
||||
|
||||
.toolbar {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 50px;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ddd;
|
||||
padding: 0;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
z-index: 100;
|
||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
||||
transition: height 0.3s ease;
|
||||
padding: 0 20px;
|
||||
justify-content: flex-start; /* 确保内容从左到右排列 */
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.toolbar.expanded {
|
||||
height: auto;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
padding-bottom: 10px;
|
||||
/* 工具栏图标容器 */
|
||||
.toolbar-icons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
margin-right: auto; /* 添加这行,确保图标靠左 */
|
||||
}
|
||||
|
||||
.toolbar-content {
|
||||
display: none;
|
||||
width: 100%;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.toolbar.expanded .toolbar-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.toolbar-toggle-btn {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
background: none;
|
||||
border: none;
|
||||
border-left: 1px solid #ddd;
|
||||
cursor: pointer;
|
||||
font-size: 0.8rem;
|
||||
color: #666;
|
||||
/* 工具栏图标 */
|
||||
.toolbar-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 6px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 101;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
font-size: 18px;
|
||||
color: #555;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.toolbar-toggle-btn:hover {
|
||||
background-color: #f5f5f5;
|
||||
.toolbar-icon:hover {
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* ==================== 下拉框样式 ==================== */
|
||||
|
||||
/* 工具栏下拉框容器 */
|
||||
.toolbar-dropdown {
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.toolbar-dropdown label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 下拉框容器 */
|
||||
.dropdown-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
/* 下拉框触发器 */
|
||||
@@ -83,16 +72,28 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
background-color: #f5f5f5;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
font-size: 13px;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.dropdown-trigger:hover {
|
||||
border-color: #1890ff;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.dropdown-arrow {
|
||||
margin-left: 8px;
|
||||
font-size: 12px;
|
||||
font-size: 10px;
|
||||
transition: transform 0.2s ease;
|
||||
}
|
||||
|
||||
.dropdown-trigger.open .dropdown-arrow {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* 下拉菜单 */
|
||||
@@ -100,23 +101,36 @@
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
min-width: 180px;
|
||||
background-color: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
z-index: 10;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
margin-top: 5px;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1001;
|
||||
margin-top: 8px;
|
||||
padding: 5px 0;
|
||||
opacity: 0;
|
||||
transform: translateY(-10px);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.dropdown-menu.visible {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* 下拉菜单项 */
|
||||
.dropdown-item {
|
||||
padding: 8px 12px;
|
||||
padding: 10px 15px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
transition: background-color 0.2s ease;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
@@ -126,6 +140,7 @@
|
||||
.dropdown-item.selected {
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 嵌套下拉框 */
|
||||
@@ -133,16 +148,60 @@
|
||||
position: absolute;
|
||||
left: 100%;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
min-width: 180px;
|
||||
background-color: white;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
|
||||
z-index: 11;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #e0e0e0;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
z-index: 1002;
|
||||
margin-left: 5px;
|
||||
padding: 5px 0;
|
||||
opacity: 0;
|
||||
transform: translateX(-10px);
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
pointer-events: none;
|
||||
/* 移除滚动条相关设置,让下拉框根据内容自动扩展 */
|
||||
}
|
||||
|
||||
.nested-dropdown .dropdown-item {
|
||||
padding-left: 20px;
|
||||
.nested-dropdown.visible {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* 添加指示箭头 */
|
||||
.dropdown-item.has-children::after {
|
||||
content: '›';
|
||||
font-size: 18px;
|
||||
color: #999;
|
||||
margin-left: 8px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.dropdown-item.selected.has-children::after {
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-container {
|
||||
margin-top: 50px; /* 为固定工具栏留出空间 */
|
||||
height: calc(100vh - 50px);
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 加载动画 */
|
||||
.loading-spinner {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid rgba(24, 144, 255, 0.2);
|
||||
border-radius: 50%;
|
||||
border-top-color: #1890ff;
|
||||
animation: spin 1s ease-in-out infinite;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import './Toolbar.css';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import './ToolBar.css';
|
||||
|
||||
const Toolbar = ({
|
||||
isExpanded,
|
||||
onToggle,
|
||||
onRoleChange,
|
||||
onChatChange
|
||||
}) => {
|
||||
@@ -11,107 +9,175 @@ const Toolbar = ({
|
||||
const [selectedChat, setSelectedChat] = useState(null);
|
||||
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
|
||||
const [roleData, setRoleData] = useState({});
|
||||
const [hoveredRole, setHoveredRole] = useState(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const dropdownRef = useRef(null);
|
||||
|
||||
// 获取角色和聊天数据
|
||||
const fetchRoleData = async () => {
|
||||
console.log('开始获取角色数据...');
|
||||
try {
|
||||
const response = await fetch('/api/tool_bar/get_all_role_and_chat', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
const fetchRoleData = async () => {
|
||||
setIsLoading(true);
|
||||
console.log('开始获取角色数据...');
|
||||
try {
|
||||
const response = await fetch('/api/tool_bar/get_all_role_and_chat', {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Cache-Control': 'no-cache',
|
||||
'Pragma': 'no-cache',
|
||||
'Expires': '0'
|
||||
}
|
||||
});
|
||||
console.log('响应状态:', response.status);
|
||||
const data = await response.json();
|
||||
console.log('获取到的数据:', data);
|
||||
setRoleData(data);
|
||||
} catch (error) {
|
||||
console.error('获取角色数据失败:', error);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 点击外部关闭下拉菜单
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event) => {
|
||||
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
|
||||
setIsDropdownOpen(false);
|
||||
setHoveredRole(null);
|
||||
}
|
||||
});
|
||||
console.log('响应状态:', response.status);
|
||||
const data = await response.json();
|
||||
console.log('获取到的数据:', data);
|
||||
setRoleData(data);
|
||||
} catch (error) {
|
||||
console.error('获取角色数据失败:', error);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener('mousedown', handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// 处理下拉框展开/收起
|
||||
const handleDropdownToggle = async () => {
|
||||
await fetchRoleData();
|
||||
setIsDropdownOpen(!isDropdownOpen);
|
||||
};
|
||||
const handleDropdownToggle = () => {
|
||||
// 每次点击都重新获取数据
|
||||
fetchRoleData();
|
||||
setIsDropdownOpen(!isDropdownOpen);
|
||||
};
|
||||
|
||||
// 处理角色选择
|
||||
const handleRoleSelect = (role) => {
|
||||
setSelectedRole(role);
|
||||
setSelectedChat(null);
|
||||
if (onRoleChange) {
|
||||
onRoleChange(role);
|
||||
}
|
||||
|
||||
// 如果该角色有聊天记录,默认选择第一个
|
||||
if (roleData[role] && roleData[role].length > 0) {
|
||||
const firstChat = roleData[role][0];
|
||||
setSelectedChat(firstChat);
|
||||
if (onChatChange) {
|
||||
onChatChange(role, firstChat);
|
||||
}
|
||||
} else {
|
||||
setSelectedChat(null);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理聊天选择
|
||||
const handleChatSelect = (chat) => {
|
||||
setSelectedChat(chat);
|
||||
setIsDropdownOpen(false);
|
||||
setHoveredRole(null);
|
||||
if (onChatChange) {
|
||||
onChatChange(selectedRole, chat);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理角色项悬停
|
||||
const handleRoleHover = (role) => {
|
||||
setHoveredRole(role);
|
||||
};
|
||||
|
||||
// 处理角色项离开
|
||||
const handleRoleLeave = () => {
|
||||
// 不立即清除hoveredRole,以便用户可以移动到二级菜单
|
||||
};
|
||||
|
||||
// 处理二级菜单进入
|
||||
const handleNestedMenuEnter = () => {
|
||||
// 防止鼠标移动时菜单消失
|
||||
};
|
||||
|
||||
// 处理二级菜单离开
|
||||
const handleNestedMenuLeave = () => {
|
||||
setHoveredRole(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`toolbar ${isExpanded ? 'expanded' : ''}`}>
|
||||
<button
|
||||
className="toolbar-toggle-btn"
|
||||
onClick={onToggle}
|
||||
>
|
||||
{isExpanded ? '▼' : '▲'}
|
||||
</button>
|
||||
<div className="toolbar">
|
||||
<div className="toolbar-icons">
|
||||
{/* Logo图标 */}
|
||||
<div className="toolbar-icon" title="首页">
|
||||
🤖
|
||||
</div>
|
||||
|
||||
{isExpanded && (
|
||||
<div className="toolbar-content">
|
||||
<div className="toolbar-dropdown">
|
||||
<label>选择角色</label>
|
||||
<div className="dropdown-container">
|
||||
<div
|
||||
className="dropdown-trigger"
|
||||
onClick={handleDropdownToggle}
|
||||
>
|
||||
{selectedRole || '选择角色'}
|
||||
<span className="dropdown-arrow">▼</span>
|
||||
</div>
|
||||
{/* 角色选择下拉框 */}
|
||||
<div className="dropdown-container" ref={dropdownRef}>
|
||||
<div
|
||||
className="toolbar-icon"
|
||||
onClick={handleDropdownToggle}
|
||||
title="选择角色"
|
||||
>
|
||||
👤
|
||||
</div>
|
||||
|
||||
{isDropdownOpen && (
|
||||
<div className="dropdown-menu">
|
||||
{Object.keys(roleData).map(role => (
|
||||
<div
|
||||
key={role}
|
||||
className={`dropdown-item ${selectedRole === role ? 'selected' : ''}`}
|
||||
onClick={() => handleRoleSelect(role)}
|
||||
>
|
||||
{role}
|
||||
{selectedRole === role && (
|
||||
<div className="nested-dropdown">
|
||||
{roleData[role].map(chat => (
|
||||
<div
|
||||
key={chat}
|
||||
className={`dropdown-item ${selectedChat === chat ? 'selected' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleChatSelect(chat);
|
||||
}}
|
||||
>
|
||||
{chat}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{isDropdownOpen && (
|
||||
<div className="dropdown-menu visible">
|
||||
{isLoading ? (
|
||||
<div className="dropdown-item">
|
||||
加载中...
|
||||
</div>
|
||||
) : (
|
||||
Object.keys(roleData).map(role => (
|
||||
<div
|
||||
key={role}
|
||||
className={`dropdown-item ${selectedRole === role ? 'selected' : ''} ${roleData[role] && roleData[role].length > 0 ? 'has-children' : ''}`}
|
||||
onClick={() => handleRoleSelect(role)}
|
||||
onMouseEnter={() => handleRoleHover(role)}
|
||||
onMouseLeave={handleRoleLeave}
|
||||
>
|
||||
{role}
|
||||
{/* 当悬停在角色上时显示二级菜单 */}
|
||||
{hoveredRole === role && roleData[role] && roleData[role].length > 0 && (
|
||||
<div
|
||||
className={`nested-dropdown visible`}
|
||||
onMouseEnter={handleNestedMenuEnter}
|
||||
onMouseLeave={handleNestedMenuLeave}
|
||||
>
|
||||
{roleData[role].map(chat => (
|
||||
<div
|
||||
key={chat}
|
||||
className={`dropdown-item ${selectedChat === chat ? 'selected' : ''}`}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleChatSelect(chat);
|
||||
}}
|
||||
>
|
||||
{chat}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 其他工具栏图标 */}
|
||||
<div className="toolbar-icon" title="设置">
|
||||
⚙️
|
||||
</div>
|
||||
<div className="toolbar-icon" title="帮助">
|
||||
❓
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,99 +1,61 @@
|
||||
/* ==================== 全局样式 ==================== */
|
||||
|
||||
/* 全局重置与基础设置 */
|
||||
/* 重置样式 */
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
html, body, .app {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: hidden; /* 禁止全局滚动 */
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
overflow: hidden; /* 防止出现滚动条 */
|
||||
}
|
||||
|
||||
/* 布局容器 */
|
||||
#root {
|
||||
.app {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* 滚动条美化 */
|
||||
::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #ccc;
|
||||
border-radius: 3px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #aaa;
|
||||
}
|
||||
|
||||
/* ==================== 主内容区域 ==================== */
|
||||
|
||||
/* 主内容区域 */
|
||||
.main-container {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
flex: 1; /* 这会让主容器占据剩余的所有空间 */
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
height: 100%; /* 确保高度填满 */
|
||||
}
|
||||
|
||||
/* 左侧栏 */
|
||||
.sidebar-left {
|
||||
width: 20%;
|
||||
background-color: #fff;
|
||||
border-right: 1px solid #ddd;
|
||||
overflow-y: auto;
|
||||
height: 100%;
|
||||
width: 250px; /* 或者你想要的宽度 */
|
||||
height: 继承父元素高度; /* 确保高度填满 */
|
||||
overflow-y: auto; /* 内容过多时显示滚动条 */
|
||||
}
|
||||
|
||||
/* 中间栏:聊天框 */
|
||||
/* 中间聊天区域 */
|
||||
.chat-area {
|
||||
flex: 3;
|
||||
background-color: #fafafa;
|
||||
height: 100%;
|
||||
flex: 1; /* 占据剩余空间 */
|
||||
height: 100%; /* 确保高度填满 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
overflow: hidden; /* 防止内容溢出 */
|
||||
}
|
||||
|
||||
/* 右侧栏 */
|
||||
.sidebar-right {
|
||||
width: 20%;
|
||||
background-color: #fff;
|
||||
border-left: 1px solid #ddd;
|
||||
width: 300px; /* 或者你想要的宽度 */
|
||||
height: 100%; /* 确保高度填满 */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* 右侧上下分割 */
|
||||
.right-top, .right-bottom {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
/* 右侧栏顶部 */
|
||||
.right-top {
|
||||
border-bottom: 1px solid #ddd;
|
||||
flex: 1; /* 占据剩余空间 */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/* 右侧栏底部 */
|
||||
.right-bottom {
|
||||
height: 200px; /* 或者你想要的高度 */
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user