main
wangyunfei 1 day ago
parent 309ddb6e4a
commit 471531c578

@ -344,7 +344,7 @@
// position: fixed; // position: fixed;
left: 0; left: 0;
right: 0; right: 0;
// bottom: -10vh; margin-bottom: 10vh;
// background: linear-gradient(to top, #f5f7fb 40%, rgba(245, 247, 251, 0)); // background: linear-gradient(to top, #f5f7fb 40%, rgba(245, 247, 251, 0));
// padding: 32px 0 28px; // padding: 32px 0 28px;
z-index: 20; z-index: 20;

@ -0,0 +1,524 @@
import React, { useState, useEffect ,useRef} from 'react'
import { history, Outlet, useModel, useDispatch, useLocation } from '@umijs/max'
import styles from './TopNavBar.less'
import {
Menu, Row, Col,
Avatar, Dropdown, Button,
Layout, theme, Divider, Tooltip, Popover
} from 'antd'
import { getPageQuery } from '@/utils/utils'
import Logo from '@/assets/logo.png'
import UserAvatar from '@/assets/boy.png'
import {
dataAnalysisStore,
conversationStore,
writingStore,
mobileStore,
assistantStore
} from '@/utils/pageConversationStore'
import { renderPageContent } from './form/RenderPageContentForm'
import {
SettingOutlined,
LogoutOutlined,
PlusOutlined,
MessageOutlined,
DeleteOutlined,
HistoryOutlined,
DownOutlined,
RobotOutlined,
BarChartOutlined,
CommentOutlined,
EditOutlined as WritingIcon,
MobileOutlined,
RightCircleOutlined,
LeftCircleOutlined,
AppstoreAddOutlined,
AppstoreOutlined,
ApiOutlined,
DeploymentUnitOutlined,
BranchesOutlined,
DatabaseOutlined,
FileTextOutlined,
} from '@ant-design/icons';
const { Content, Sider } = Layout;
function getItem(label, key, icon, children) {
return {
key,
icon,
children,
label,
};
}
const menuItem = [
{
label: 'AI助手',
key: 'aiqa',
icon: '🤖',
children: [
{ label: '智能对话', key: '/topnavbar00/aiqa/conversation', icon: <MessageOutlined style={{ color: '#1677ff', marginRight: 8 }} /> },
{ label: '智能写作', key: '/topnavbar00/aiqa/writing', icon: <WritingIcon style={{ color: '#fa8c16', marginRight: 8 }} /> },
{ label: '智能助理', key: '/topnavbar00/aiqa/assistant', icon: <RobotOutlined style={{ color: '#52c41a', marginRight: 8 }} /> },
{ label: '数据分析', key: '/topnavbar00/aiqa/dataanalysis', icon: <BarChartOutlined style={{ color: '#1890ff', marginRight: 8 }} /> },
{ label: '问答移动端', key: '/topnavbar00/aiqa/mobile', icon: <MobileOutlined style={{ color: '#13c2c2', marginRight: 8 }} /> },
]
},
{
label: '系统管理',
key: 'system',
icon: '⚙️',
children: [
{ label: '插件安装', key: '/topnavbar00/system/plugininstall', icon: <AppstoreAddOutlined style={{ color: '#722ed1', marginRight: 8 }} /> },
{ label: '插件管理', key: '/topnavbar00/system/pluginmanage', icon: <AppstoreOutlined style={{ color: '#2f54eb', marginRight: 8 }} /> },
{ label: '助理配置', key: '/topnavbar00/system/assistantconfig', icon: <SettingOutlined style={{ color: '#faad14', marginRight: 8 }} /> },
{ label: '模型接入', key: '/topnavbar00/system/model', icon: <ApiOutlined style={{ color: '#13c2c2', marginRight: 8 }} /> },
{ label: '应用嵌入', key: '/topnavbar00/system/embed', icon: <DeploymentUnitOutlined style={{ color: '#eb2f96', marginRight: 8 }} /> },
{ label: '工作流配置', key: '/topnavbar00/system/workflow', icon: <BranchesOutlined style={{ color: '#52c41a', marginRight: 8 }} /> },
{ label: '知识库管理', key: '/topnavbar00/system/knowledge', icon: <DatabaseOutlined style={{ color: '#1890ff', marginRight: 8 }} /> },
{ label: '提示词模板管理', key: '/topnavbar00/system/prompts', icon: <FileTextOutlined style={{ color: '#fa8c16', marginRight: 8 }} /> },
]
}
]
const TopNavBar = (props) => {
const dispatch = useDispatch()
const { initialState: { menu }, setInitialState } = useModel('@@initialState')
// 测试时候放开启用本地菜单
window.dynamicRoute = menuItem
const dynamicRoute = window.dynamicRoute
const location = useLocation()
const pathName = location.pathname
const [activeKey, setActiveKey] = useState(pathName ?? '/topnavbar00/aiqa/conversation')
const [openKeys, setOpenKeys] = useState([])
const firstLoadRef = useRef(true)
const [menuItems, setMenuItems] = useState([])
const [expandedPage, setExpandedPage] = useState('conversation')
const conversationExpanded = expandedPage === 'conversation'
const writingExpanded = expandedPage === 'writing'
const dataAnalysisExpanded = expandedPage === 'dataanalysis'
const assistantExpanded = expandedPage === 'assistant'
const mobileExpanded = expandedPage === 'mobile'
const toggleExpand = (page) => {
setExpandedPage(prev => prev === page ? null : page)
}
// 每个页面的对话状态
const [dataAnalysisConversations, setDataAnalysisConversations] = useState(dataAnalysisStore.getConversations())
const [conversationConversations, setConversationConversations] = useState(conversationStore.getConversations())
const [writingConversations, setWritingConversations] = useState(writingStore.getConversations())
const [assistantConversations, setAssistantConversations] = useState(assistantStore.getConversations())
const [mobileConversations, setMobileConversations] = useState(mobileStore.getConversations())
const [collapsed, setCollapsed] = useState(false);
const toggleCollapsed = () => setCollapsed(c => !c);
useEffect(() => {
if (!dynamicRoute || dynamicRoute?.length === 0) return
let newList = []
if (dynamicRoute?.length) {
dynamicRoute?.map(item => {
newList.push({
key: item?.key,
label: item?.label,
icon: item?.icon,
children: item?.children?.map(child => ({
key: child?.key,
label: child?.label,
icon: child?.icon,
}))
})
})
// 设置当前激活的菜单项
const currentActiveKey = newList?.find(item =>
item.children?.some(child => pathName.indexOf(child.key) !== -1)
)?.children?.find(child => pathName.indexOf(child.key) !== -1)?.key ?? ''
setActiveKey(currentActiveKey)
// 设置默认展开的菜单
const currentOpenKey = newList?.find(item =>
item.children?.some(child => pathName.indexOf(child.key) !== -1)
)?.key ?? ''
if (!firstLoadRef.current) {
if (currentOpenKey) {
setOpenKeys([currentOpenKey])
}
} else {
firstLoadRef.current = false
}
}
setMenuItems(newList)
}, [dynamicRoute, pathName])
// 订阅每个页面的对话状态变化
useEffect(() => {
const unsubscribeDataAnalysis = dataAnalysisStore.subscribe(({ conversations }) => {
setDataAnalysisConversations(conversations)
})
const unsubscribeConversation = conversationStore.subscribe(({ conversations }) => {
setConversationConversations(conversations)
})
const unsubscribeWriting = writingStore.subscribe(({ conversations }) => {
setWritingConversations(conversations)
})
const unsubscribeAssistant = assistantStore.subscribe(({ conversations }) => {
setAssistantConversations(conversations)
})
const unsubscribeMobile = mobileStore.subscribe(({ conversations }) => {
setMobileConversations(conversations)
})
return () => {
unsubscribeDataAnalysis()
unsubscribeConversation()
unsubscribeWriting()
unsubscribeAssistant()
unsubscribeMobile()
}
}, [])
const setRouteActive = value => {
const curKey = value.key
setActiveKey(curKey)
history.replace(curKey)
}
// 处理一级菜单展开/收缩
const handleMenuGroupClick = (menuKey) => {
if (openKeys.includes(menuKey)) {
// 如果已展开,则收缩
setOpenKeys(openKeys.filter(key => key !== menuKey))
} else {
// 如果已收缩,则展开
setOpenKeys([...openKeys, menuKey])
}
}
const loginOut = async () => {
// await outLogin()
const { redirect } = getPageQuery()
if (window.location.pathname !== '/login/login' && !redirect) {
history.replace({
pathname: '/login',
})
setInitialState({ currentUser: null, menu: null, menuMap: null })
window.dynamicRoute = null
localStorage.clear()
}
}
const handleMenuClick = (e) => {
switch (e.key) {
case 'logout':
loginOut()
break
default:
break
}
}
const dropDownMenuItems = [
{
label: <><LogoutOutlined style={{ marginRight: '8px' }} />退出登录</>,
key: 'logout'
}
]
const dropDownMenu = () => (
<Menu items={dropDownMenuItems} onClick={handleMenuClick} selectedKeys={[]} className={styles.tabBarMenu} />
)
const {
token: { colorBgContainer, borderRadiusLG },
} = theme.useToken();
const userNameContent = (
<div>
<div>用户小智</div>
<a href='https://help.openai.com/en'
target="_blank"
rel="noopener noreferrer"
className={styles.userLink}
style={{ color: '#000', margin: "0px", padding: "0px" }}
>帮助中心</a>
<div></div>
<a href='https://cdn.deepseek.com/policies/zh-CN/deepseek-terms-of-use.html'
target="_blank"
rel="noopener noreferrer"
className={styles.userLink}
style={{ color: '#000', margin: "0px", padding: "0px" }}
>
用户协议</a>
{/* <span className={styles.tabBarRightName}>{userInfo?.user_name_cn ? userInfo.user_name_cn : (userInfo?.user_name || '')}</span> */}
</div>
)
return (
<div className={styles.layoutContainer}>
{/* 头部功能 */}
<div className={styles.tabBarHeader}>
<Row className={styles.tabBarRow}>
{/* 左侧logo */}
<Col xs={16} sm={16} md={16} lg={16} xl={16} className={styles.tabBarLeft}>
<img src={Logo} alt='logo' className={styles.leftLogo} />
<span className={styles.leftTopText}>AI Q&A</span>
{/* 折叠按钮 */}
<span
className={styles.collapseButton}
onClick={toggleCollapsed}
>
{collapsed ? <RightCircleOutlined /> : <LeftCircleOutlined />}
</span>
</Col>
{/* <Col xs={0} sm={8} md={8} lg={8} xl={8} className={styles.tabBarCenter}>
<span className={styles.tagline}>
你好欢迎使用 <strong>AI 助手</strong>
</span>
</Col> */}
{/* 右侧退出 */}
<Col xs={8} sm={8} md={8} lg={8} xl={8} className={styles.tabBarRight}>
<Popover content={userNameContent} className={styles.userNameContent}>
<Avatar className={styles.tabBarRightAvaTor} src={UserAvatar} />
</Popover>
{/* 用户名 */}
{/* <span className={styles.tabBarRightName}>{userInfo?.user_name_cn ? userInfo.user_name_cn : (userInfo?.user_name || '')}</span> */}
<Dropdown dropdownRender={dropDownMenu}>
<Button type='text' className={styles.tabBarRightBtn}>
<LogoutOutlined className={styles.tabBarRightExit} />
</Button>
</Dropdown>
</Col>
</Row>
</div>
{/* 内容 */}
<div className={styles.contentMain}>
<Layout style={{ height: '100%' }}>
<Sider
collapsible
collapsed={collapsed}
trigger={null}
onCollapse={setCollapsed}
width={200}
collapsedWidth={0} // 完全隐藏侧边栏
theme="light"
className={styles.sider}
>
<div className={styles.customMenu}>
{menuItems.map(item => (
<div key={item.key} className={styles.menuGroup}>
<div
className={styles.menuGroupTitle}
onClick={() => handleMenuGroupClick(item.key)}
>
{/* 一级菜单 */}
<span className={styles.menuGroupLabel}>{item.icon}{item.label}</span>
{/* 一级菜单的下拉按钮 */}
{!collapsed && (
<DownOutlined
className={styles.menuGroupArrow}
style={{
transform: openKeys.includes(item.key) ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 0.3s ease'
}}
/>
)}
</div>
{item.children && openKeys.includes(item.key) && (
<div className={styles.menuGroupItems}>
{item.children.map(child => {
// 智能对话页面
if (child.key === '/topnavbar00/aiqa/conversation') {
return (
<div key={child.key}>
<div
className={`${styles.pageMenuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => {
toggleExpand('conversation')
setRouteActive(child)
}}
>
<span style={{
textAlign: 'center',
fontSize: '13px',
fontWeight: '500'
}}>
{child.icon}{child.label}</span>
{/* <DownOutlined
className={`${styles.pageArrow} ${conversationExpanded ? styles.expanded : ''}`}
/> */}
</div>
{conversationExpanded &&
renderPageContent('conversation',
conversationConversations, conversationExpanded,
)}
</div>
)
}
// 智能写作页面
if (child.key === '/topnavbar00/aiqa/writing') {
return (
<div key={child.key}>
<div
className={`${styles.pageMenuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => {
toggleExpand('writing')
setRouteActive(child)
}}
>
<span
style={{
textAlign: 'center',
fontSize: '13px',
fontWeight: '500'
}}>
{child.icon}{child.label}</span>
{/* <DownOutlined
className={`${styles.pageArrow} ${writingExpanded ? styles.expanded : ''}`}
/> */}
</div>
{writingExpanded && renderPageContent('writing',
writingConversations, writingExpanded,)}
</div>
)
}
// 智能助理页面
if (child.key === '/topnavbar00/aiqa/assistant') {
return (
<div key={child.key}>
<div
className={`${styles.pageMenuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => {
toggleExpand('assistant')
setRouteActive(child)
}}
>
<span style={{
textAlign: 'center',
fontSize: '13px',
fontWeight: '500'
}}>
{child.icon}{child.label}</span>
{/* <DownOutlined
className={`${styles.pageArrow} ${assistantExpanded ? styles.expanded : ''}`}
/> */}
</div>
{assistantExpanded && renderPageContent('assistant',
assistantConversations, assistantExpanded,)}
</div>
)
}
// 数据分析页面
if (child.key === '/topnavbar00/aiqa/dataanalysis') {
return (
<div key={child.key}>
<div
className={`${styles.pageMenuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => {
toggleExpand('dataanalysis')
setRouteActive(child)
}}
>
<span style={{
textAlign: 'center',
fontSize: '13px',
fontWeight: '500'
}}>
{child.icon}{child.label}</span>
{/* <DownOutlined
className={`${styles.pageArrow} ${dataAnalysisExpanded ? styles.expanded : ''}`}
/> */}
</div>
{dataAnalysisExpanded && renderPageContent('dataanalysis', dataAnalysisConversations,
dataAnalysisExpanded,)}
</div>
)
}
// 问答移动端页面
if (child.key === '/topnavbar00/aiqa/mobile') {
return (
<div key={child.key}>
<div
className={`${styles.pageMenuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => {
toggleExpand('mobile')
setRouteActive(child)
setCollapsed(true) // 直接收起
}}
>
<span style={{
textAlign: 'center',
fontSize: '13px',
fontWeight: '500'
}}>
{child.icon}{child.label}</span>
{/* <DownOutlined
className={`${styles.pageArrow} ${mobileExpanded ? styles.expanded : ''}`}
/> */}
</div>
{mobileExpanded && renderPageContent('mobile', mobileConversations,
mobileExpanded,)}
</div>
)
}
// 系统管理内部页面
return (
<div
key={child.key}
className={`${styles.menuItem} ${activeKey === child.key ? styles.active : ''}`}
onClick={() => setRouteActive(child)}
>
<span style={{ width: "100%" }}>{child.icon}{child.label}</span>
</div>
)
})}
</div>
)}
</div>
))}
</div>
</Sider>
<Layout className={styles.contentLayout}>
<Content className={styles.content}>
{/* 主题内容区域 */}
<Outlet />
</Content>
</Layout>
</Layout>
</div>
</div >
)
}
export default TopNavBar

@ -7,6 +7,11 @@ import { getPageQuery } from '@/utils/utils'
import Logo from '@/assets/logo.png' import Logo from '@/assets/logo.png'
import { userInfo } from '@/utils/globalCommon' import { userInfo } from '@/utils/globalCommon'
import {
conversationStore,
} from '@/utils/pageConversationStore'
import { renderPageContent } from './form/RenderPageContentForm'
const menuItem = [ const menuItem = [
{ {
label: '效率管理', label: '效率管理',
@ -93,6 +98,20 @@ const TopNavBar = (props) => {
const [activeKey, setActiveKey] = useState(pathName ?? '/topnavbar00/home') const [activeKey, setActiveKey] = useState(pathName ?? '/topnavbar00/home')
const [menuItems, setMenuItems] = useState([]) const [menuItems, setMenuItems] = useState([])
const [expandedPage, setExpandedPage] = useState('conversation')
const conversationExpanded = expandedPage === 'conversation'
const toggleExpand = (page) => {
setExpandedPage(prev => prev === page ? null : page)
}
const [conversationConversations, setConversationConversations] = useState(conversationStore.getConversations())
const [collapsed, setCollapsed] = useState(false);
const toggleCollapsed = () => setCollapsed(c => !c);
useEffect(() => { useEffect(() => {
if (!dynamicRoute || dynamicRoute?.length === 0) return if (!dynamicRoute || dynamicRoute?.length === 0) return
let newList = [] let newList = []
@ -102,7 +121,12 @@ const TopNavBar = (props) => {
newList.push({ newList.push({
key: item?.key, key: item?.key,
label: item?.label, label: item?.label,
icon: item?.icon icon: item?.icon,
children: item?.children?.map(child => ({
key: child?.key,
label: child?.label,
// icon: child?.icon,
}))
}) })
}) })
@ -112,6 +136,20 @@ const TopNavBar = (props) => {
setMenuItems(newList) setMenuItems(newList)
}, [dynamicRoute]) }, [dynamicRoute])
useEffect(() => {
const unsubscribeConversation = conversationStore.subscribe(({ conversations }) => {
setConversationConversations(conversations)
})
return () => {
unsubscribeConversation()
}
}, [])
const setRouteActive = value => { const setRouteActive = value => {
const curKey = value.key const curKey = value.key
const activeKeys = menuItems?.filter(item => curKey.indexOf(item.key) !== -1)[0]?.key ?? '' const activeKeys = menuItems?.filter(item => curKey.indexOf(item.key) !== -1)[0]?.key ?? ''
@ -172,7 +210,6 @@ const TopNavBar = (props) => {
{/* <Col xs={12} sm={12} md={12} lg={12} xl={12} className={styles.tabBarLeft}> {/* <Col xs={12} sm={12} md={12} lg={12} xl={12} className={styles.tabBarLeft}>
<img src={Logo} alt='logo' className={styles.leftLogo} /> <img src={Logo} alt='logo' className={styles.leftLogo} />
<Menu mode='horizontal' className={styles.leftMenu} selectedKeys={[activeKey]} items={menuItems} onClick={value => setRouteActive(value)} /> <Menu mode='horizontal' className={styles.leftMenu} selectedKeys={[activeKey]} items={menuItems} onClick={value => setRouteActive(value)} />
</Col> */} </Col> */}
@ -188,8 +225,11 @@ const TopNavBar = (props) => {
</Row> </Row>
</div> </div>
{/* 修改当路由为智能对话页时渲染历史会话组件renderPageContent其它路由不变 */}
<div className={styles.contentMain} style={{ height: 'auto', backgroundColor: 'inherit' }}> <div className={styles.contentMain} style={{ height: 'auto', backgroundColor: 'inherit' }}>
<Outlet /> <Outlet />
{/* {renderPageContent('conversation', conversationConversations, conversationExpanded)} */}
</div> </div>
{/* 底部版权信息 */} {/* 底部版权信息 */}
<div className='footerCopyright' style={{ <div className='footerCopyright' style={{

@ -0,0 +1,176 @@
import React from "react"
import { Button, Tooltip, Divider } from 'antd'
import { history } from '@umijs/max'
import { PlusOutlined, MessageOutlined, DeleteOutlined, HistoryOutlined } from '@ant-design/icons'
import styles from './RenderPageContentForm.less'
import {
dataAnalysisStore,
conversationStore,
writingStore,
mobileStore,
assistantStore
} from '@/utils/pageConversationStore'
// 渲染页面展开内容 - 通用函数
export const renderPageContent = (
pageType, conversations, expanded, setExpanded,) => {
if (!expanded) return null
const storeMap = {
dataanalysis: { store: dataAnalysisStore, path: '/topnavbar00/hrefficiency/dataanalysis' },
conversation: { store: conversationStore, path: '/topnavbar00/hrefficiency/ChatConversation' },
writing: { store: writingStore, path: '/topnavbar00/hrefficiency/writing' },
assistant: { store: assistantStore, path: '/topnavbar00/hrefficiency/assistant' },
mobile: { store: mobileStore, path: '/topnavbar00/hrefficiency/mobile' }
}
// 创建新对话 - 根据页面类型
const createNewConversation = (pageType) => {
switch (pageType) {
case 'dataanalysis':
dataAnalysisStore.createNewConversation()
history.replace('/topnavbar00/hrefficiency/dataanalysis')
break
case 'conversation':
conversationStore.createNewConversation()
history.replace('/topnavbar00/hrefficiency/ChatConversation')
break
case 'writing':
writingStore.createNewConversation()
history.replace('/topnavbar00/hrefficiency/writing')
break
case 'assistant':
assistantStore.createNewConversation()
history.replace('/topnavbar00/hrefficiency/assistant')
break
case 'mobile':
mobileStore.createNewConversation()
history.replace('/topnavbar00/hrefficiency/mobile')
break
default:
break
}
}
// 删除对话 - 根据页面类型
const deleteConversation = (conversationId, pageType) => {
switch (pageType) {
case 'dataanalysis':
dataAnalysisStore.deleteConversation(conversationId)
break
case 'conversation':
conversationStore.deleteConversation(conversationId)
break
case 'writing':
writingStore.deleteConversation(conversationId)
break
case 'assistant':
assistantStore.deleteConversation(conversationId)
break
case 'mobile':
mobileStore.deleteConversation(conversationId)
break
default:
break
}
}
// 切换对话 - 根据页面类型
const switchConversation = (conversationId, pageType) => {
switch (pageType) {
case 'dataanalysis':
dataAnalysisStore.switchConversation(conversationId)
history.replace('/topnavbar00/hrefficiency/dataanalysis')
break
case 'conversation':
conversationStore.switchConversation(conversationId)
history.replace('/topnavbar00/hrefficiency/ChatConversation')
break
case 'writing':
writingStore.switchConversation(conversationId)
history.replace('/topnavbar00/hrefficiency/writing')
break
case 'assistant':
assistantStore.switchConversation(conversationId)
history.replace('/topnavbar00/hrefficiency/assistant')
break
case 'mobile':
mobileStore.switchConversation(conversationId)
history.replace('/topnavbar00/hrefficiency/mobile')
break
default:
break
}
}
return (
<div className={styles.pageExpandedContent}>
<div className={styles.conversationsList}>
<div className={styles.conversationsTitle}>
<HistoryOutlined />
<span>历史会话</span>
<Divider type="vertical" style={{ borderColor: '#666', margin: '0 0' }} />
{/* 新对话 */}
<Tooltip
title="新会话"
color="#fff"
overlayInnerStyle={{ color: '#222', fontWeight: 400, fontSize: 12 }}
>
<Button
type="primary"
icon={<PlusOutlined />}
onClick={() => createNewConversation(pageType)}
block
className={styles.newChatBtn}
/>
</Tooltip>
</div>
<div className={styles.conversationsContainer}>
{conversations.map((conversation) => (
<div
key={conversation.id}
className={`${styles.conversationItem} ${conversation.isActive ? styles.active : ''}`}
onClick={() => switchConversation(conversation.id, pageType)}
>
<div className={styles.conversationContent}>
<div className={styles.conversationTitle}>
<MessageOutlined className={styles.conversationIcon} />
<span className={styles.titleText} title={conversation.title}>
{conversation.title}
</span>
</div>
<div className={styles.conversationTime}>
{conversation.lastUpdate.toLocaleDateString()}
</div>
</div>
<div className={styles.conversationActions}>
<Tooltip title="删除对话"
color="#fff"
overlayInnerStyle={{ color: '#222', fontWeight: 400, fontSize: 12 }}>
<Button
type="text"
size="small"
icon={<DeleteOutlined />}
onClick={(e) => {
e.stopPropagation()
deleteConversation(conversation.id, pageType)
}}
danger
/>
</Tooltip>
</div>
</div>
))}
</div>
</div>
</div>
)
}
export default renderPageContent

@ -0,0 +1,782 @@
// .layoutContainer {
// height: 100vh;
// background: #fff;
// display: flex;
// flex-direction: column;
// overflow-y: auto;
// // 顶部栏
// .tabBarHeader {
// // background: rgba(255, 255, 255, 0.95);135deg, #667eea 0%, #764ba2 100%
// padding: 0;
// width: 100%;
// height: 65px;
// margin-bottom: -4px;
// border-bottom: 1px solid rgba(0, 0, 0, 0.06);
// box-shadow: 0 2px 4px rgba(31, 35, 41, 0.04);
// background:
// linear-gradient(120deg, #ffffff 0%, #f6f9ff 55%, #fff 100%);
// .tabBarRow {
// padding: 0 24px;
// height: 100%;
// display: flex;
// align-items: center;
// // position: relative;
// .tabBarLeft {
// display: flex;
// justify-content: flex-start;
// flex-wrap: nowrap;
// align-items: center;
// .leftLogo {
// width: 40px;
// height: 40px;
// margin-right: 11px;
// margin-top: -8px;
// border-radius: 8px;
// }
// .leftTopText {
// font-size: 24px;
// height: 40px;
// font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
// font-weight: 600;
// background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
// -webkit-background-clip: text;
// -webkit-text-fill-color: transparent;
// background-clip: text;
// letter-spacing: 0.02em;
// }
// .collapseButton {
// color: #8f8f8f;
// margin-left: 10px;
// margin-top: -8px;
// font-size: 20px;
// transition: none !important;
// :global {
// .ant-layout-sider {
// transition: none !important;
// }
// }
// &:hover {
// color: #000;
// // cursor:pointer;
// cursor: pointer;
// }
// }
// }
// .tabBarRight {
// text-align: right;
// display: flex;
// justify-content: flex-end;
// flex-wrap: nowrap;
// align-items: center;
// .tabBarRightAvaTor {
// margin-right: 2px;
// margin-top: -1px;
// border: 2px solid rgba(102, 126, 234, 0.2);
// }
// .tabBarRightName {
// margin-right: 0px;
// font-weight: 500;
// color: #333;
// }
// .tabBarRightBtn {
// height: 40px;
// width: 40px;
// // border-radius: 6px;
// background: transparent;
// // background: rgba(102, 126, 234, 0.1);
// border-color: transparent;
// // border: 1px solid rgba(102, 126, 234, 0.2);
// color: #666;
// font-size: 18px;
// &:hover {
// background: transparent;
// border-color: transparent;
// }
// }
// .userNameContent {
// width: 33px;
// height: 33px;
// background-color: #fff;
// box-shadow: transparent;
// }
// }
// }
// }
// // 内容
// .contentMain {
// flex: 1;
// display: flex;
// overflow: hidden;
// background: rgba(255, 255, 255);
// .sider {
// background: rgba(255, 255, 255);
// overflow-y: auto;
// overflow-x: hidden;
// &::-webkit-scrollbar {
// width: 6px;
// }
// &::-webkit-scrollbar-track {
// background: rgba(255, 255, 255);
// }
// &::-webkit-scrollbar-thumb {
// background: rgba(255, 255, 255);
// &:hover {
// background: rgba(255, 255, 255);
// }
// }
// .sideMenu {
// border-right: none;
// background-color: transparent;
// padding: 16px 0;
// :global(.ant-menu-submenu) {
// margin: 4px 12px;
// border-radius: 8px;
// overflow: hidden;
// .ant-menu-submenu-title {
// height: 48px;
// line-height: 48px;
// border-radius: 8px;
// margin: 0;
// font-weight: 500;
// color: #333;
// transition: all 0.3s ease;
// &:hover {
// background: rgba(255, 255, 255);
// color: #667eea;
// }
// .ant-menu-submenu-arrow {
// color: #667eea;
// }
// }
// &.ant-menu-submenu-open>.ant-menu-submenu-title {
// background: rgba(255, 255, 255);
// color: #667eea;
// }
// }
// :global(.ant-menu-item) {
// margin: 2px 12px;
// border-radius: 6px;
// height: 40px;
// line-height: 40px;
// padding-left: 24px !important;
// font-size: 14px;
// transition: all 0.3s ease;
// &:hover {
// background: rgba(255, 255, 255);
// color: #667eea;
// }
// &.ant-menu-item-selected {
// background: rgba(255, 255, 255);
// color: #667eea;
// font-weight: 500;
// border-right: 3px solid #667eea;
// }
// }
// :global(.ant-menu-submenu-inline > .ant-menu) {
// background: rgba(255, 255, 255, 0.5);
// border-radius: 8px;
// margin: 8px 0;
// }
// }
// // 自定义菜单样式
// .customMenu {
// padding: 8px 0 16px 0;
// margin: 10px 0px 0px 9px;
// position: relative;
// border: 1px solid rgba(0, 0, 0, 0.06);
// border-radius: 8px;
// background:
// linear-gradient(#ffffff, #ffffff) padding-box,
// linear-gradient(135deg, rgba(102, 126, 234, 0.25), rgba(118, 75, 162, 0.25)) border-box;
// box-shadow: 0 2px 6px rgba(0, 0, 0, 0.04);
// backdrop-filter: blur(2px);
// &:before {
// content: '';
// position: absolute;
// left: 0;
// top: 6px;
// bottom: 6px;
// width: 3px;
// border-radius: 2px;
// // background: linear-gradient(180deg, #667eea, #764ba2);
// }
// .menuGroup {
// margin-bottom: 16px;
// .menuGroupTitle {
// display: flex;
// align-items: center;
// justify-content: space-between;
// padding: 12px 16px;
// font-weight: 500;
// color: #030303;
// cursor: pointer;
// transition: background-color 0.2s ease;
// &:hover {
// background-color: #fafafa;
// }
// .menuGroupLabel {
// flex: 1;
// font-size: 16px;
// text-align: center;
// &:hover {
// background-color: #fafafa;
// }
// }
// .menuGroupArrow {
// font-size: 12px;
// color: #999;
// transition: transform 0.3s ease;
// }
// }
// .menuGroupItems {
// .menuItem {
// display: flex;
// align-items: center;
// text-align: center;
// padding: 8px 16px 8px 16px;
// margin: 2px 12px;
// border-radius: 6px;
// height: 40px;
// line-height: 24px;
// font-size: 13px;
// color: #030303;
// font-weight: 500;
// cursor: pointer;
// transition: all 0.3s ease;
// &:hover {
// background-color: #fafafa;
// color: #030303;
// }
// &.active {
// background-color: #fafafa;
// color: #030303;
// font-weight: 500;
// }
// }
// .assistantMenuItem {
// display: flex;
// align-items: center;
// justify-content: space-between;
// padding: 8px 16px 8px 16px;
// margin: 2px 12px;
// border-radius: 6px;
// height: 40px;
// line-height: 24px;
// font-size: 14px;
// color: #333;
// cursor: pointer;
// transition: all 0.3s ease;
// &:hover {
// background: rgba(102, 126, 234, 0.08);
// color: #667eea;
// }
// &.active {
// background: linear-gradient(135deg, rgba(102, 126, 234, 0.15) 0%, rgba(118, 75, 162, 0.15) 100%);
// color: #667eea;
// font-weight: 500;
// border-right: 3px solid #667eea;
// // box-shadow: 0 2px 8px rgba(102, 126, 234, 0.2);
// }
// .assistantArrow {
// font-size: 12px;
// color: #999;
// transition: transform 0.3s ease;
// &.expanded {
// transform: rotate(180deg);
// }
// }
// }
// // 页面菜单项样式
// .pageMenuItem {
// display: flex;
// align-items: center;
// position: relative;
// justify-content: center;
// padding: 10px 14px;
// cursor: pointer;
// transition: all 0.2s ease;
// border-radius: 6px;
// margin: 4px 8px;
// font-size: 12px;
// &:hover {
// background: #f5f5f5;
// }
// &.active {
// background: #f5f5f5;
// }
// span {
// flex: 1;
// text-align: center;
// }
// .pageArrow {
// margin-left: auto;
// font-size: 12px;
// color: #999;
// transition: transform 0.3s ease;
// &.expanded {
// transform: rotate(180deg);
// }
// }
// }
// }
// }
// }
// // 智能助理展开内容样式
// .assistantExpandedContent {
// margin: 0 12px 16px 16px;
// background: rgba(255, 255, 255, 0.8);
// border-radius: 8px;
// padding: 12px;
// .assistantHeader {
// margin-bottom: 8px;
// }
// // .conversationsList {
// // // .conversationsTitle {
// // // display: flex;
// // // align-items: center;
// // // width: 100%;
// // // gap: 8px;
// // // font-size: 12px;
// // // font-weight: 500;
// // // // color: #666;
// // // color: pink;
// // // margin-bottom: 8px;
// // // padding: 0 4px;
// // // :global {
// // // .ant-btn-primary {
// // // background: #666 !important;
// // // }
// // // }
// // // .anticon {
// // // color: #999;
// // // font-size: 14px;
// // // }
// // // }
// // .conversationsContainer {
// // max-height: 200px;
// // overflow-y: auto;
// // padding-right: 4px;
// // // 自定义滚动条样式
// // &::-webkit-scrollbar {
// // width: 4px;
// // }
// // &::-webkit-scrollbar-track {
// // background: #f1f1f1;
// // border-radius: 2px;
// // }
// // &::-webkit-scrollbar-thumb {
// // background: #c1c1c1;
// // border-radius: 2px;
// // }
// // &::-webkit-scrollbar-thumb:hover {
// // background: #a8a8a8;
// // }
// // .conversationItem {
// // display: flex;
// // align-items: center;
// // justify-content: space-between;
// // padding: 8px;
// // margin-bottom: 6px;
// // border-radius: 6px;
// // cursor: pointer;
// // transition: all 0.2s ease;
// // border: 1px solid transparent;
// // &:hover {
// // background: #f5f5f5;
// // border-color: #e6e6e6;
// // .conversationActions {
// // opacity: 1;
// // }
// // }
// // &.active {
// // background: #e6f7ff;
// // border-color: #91d5ff;
// // .conversationTitle .titleText {
// // color: #1890ff;
// // font-weight: 500;
// // }
// // }
// // .conversationContent {
// // flex: 1;
// // min-width: 0;
// // .conversationTitle {
// // display: flex;
// // align-items: center;
// // gap: 6px;
// // margin-bottom: 2px;
// // .conversationIcon {
// // color: #52c41a;
// // font-size: 12px;
// // }
// // .titleText {
// // font-size: 13px;
// // color: #333;
// // overflow: hidden;
// // text-overflow: ellipsis;
// // white-space: nowrap;
// // max-width: 100px;
// // }
// // }
// // .conversationTime {
// // font-size: 11px;
// // color: #999;
// // }
// // }
// // .conversationActions {
// // opacity: 0;
// // transition: opacity 0.2s ease;
// // .ant-btn {
// // padding: 2px;
// // height: 20px;
// // width: 20px;
// // font-size: 12px;
// // &:hover {
// // background: rgba(0, 0, 0, 0.05);
// // }
// // }
// // }
// // }
// // }
// // }
// }
// }
// .contentLayout {
// flex: 1;
// background: transparent;
// overflow: hidden;
// .content {
// height: 100%;
// padding: 8px 12px 8px 12px;
// background-color: #fff;
// overflow-y: auto;
// overflow-x: hidden;
// &::-webkit-scrollbar {
// width: 8px;
// }
// &::-webkit-scrollbar-track {
// // background: rgba(255, 255, 255, 0.1);
// border-radius: 4px;
// }
// &::-webkit-scrollbar-thumb {
// // background: rgba(102, 126, 234, 0.3);
// border-radius: 4px;
// &:hover {
// // background: rgba(102, 126, 234, 0.5);
// }
// }
// }
// }
// }
// }
// 用户头像悬浮样式 - 强制覆盖 Ant Design 默认样式
:global(.ant-popover) {
.ant-popover-title {
width: 150px !important;
min-width: 150px !important;
max-width: 150px !important;
text-align: center !important;
text-align-last: center !important;
text-align: center !important;
}
.ant-popover-inner-content {
color: rgba(0, 0, 0, 0.88) !important;
justify-content: center !important;
align-items: center !important;
display: flex !important;
flex-direction: column !important;
padding: 10px !important;
text-align: center !important;
text-align-last: center !important;
text-align: center !important;
}
// 确保所有文本内容都居中
.ant-popover-inner-content p {
text-align: center !important;
margin: 0 !important;
padding: 2px 0 !important;
width: 100% !important;
text-align: center;
}
// 强制覆盖内容区域宽度和居中
.ant-popover-content {
min-width: 150px !important;
max-width: 150px !important;
text-align: center !important;
}
.ant-popover-inner {
min-width: 150px !important;
max-width: 150px !important;
text-align: center !important;
}
}
.pageExpandedContent {
margin: 4px 14px 4px 12px;
padding: 6px 10px 8px 10px;
width: 12vw;
background: #fff;
display: flex;
border: 1px solid #e5e5e5; // 新增外边框
border-radius: 6px;
.newChatBtn {
// margin-left: auto;
display: inline-flex;
align-items: center;
justify-content: center;
height: 20px;
width: 20px;
border-radius: 6px;
}
.conversationsList {
.conversationsTitle {
display: flex;
align-items: center;
gap: 6px;
width: 46vw;
font-size: 13px;
font-weight: 500;
color: #666;
margin-bottom: 8px;
padding: 0 2px;
:global {
.ant-btn-primary {
background: rgba(153, 153, 153, 0.5) !important;
box-shadow: none !important; // 阴影
&:hover {
background: rgba(153, 153, 153, 0.8) !important;
}
}
}
.anticon {
color: #999;
font-size: 12px;
}
}
.conversationsContainer {
max-height: 200px;
overflow-y: auto;
// 自定义滚动条样式
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb {
background: #c1c1c1;
border-radius: 2px;
}
&::-webkit-scrollbar-thumb:hover {
background: #a8a8a8;
}
}
.conversationItem {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 10px;
margin-bottom: 6px;
width: 10.5vw;
border-radius: 6px;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid transparent;
&:hover {
background: #f0f0f0;
.conversationActions {
opacity: 1;
}
}
&.active {
background: #e6f7ff;
border-color: #91d5ff;
.conversationTitle .titleText {
color: #1890ff;
font-weight: 500;
}
}
.conversationContent {
flex: 1;
min-width: 0;
.conversationTitle {
display: flex;
align-items: center;
gap: 6px;
margin-bottom: 2px;
.conversationIcon {
color: #1890ff;
font-size: 12px;
}
.titleText {
font-size: 12px;
color: #333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 100px;
}
}
.conversationTime {
font-size: 11px;
color: #999;
}
}
.conversationActions {
opacity: 0;
transition: opacity 0.2s ease;
display: flex;
gap: 2px;
.ant-btn {
padding: 2px;
height: 20px;
width: 20px;
font-size: 10px;
&:hover {
background: rgba(0, 0, 0, 0.05);
}
}
}
}
}
}
// 智能助理特殊样式(保持兼容性)
.assistantMenuItem {
@extend .pageMenuItem;
}
.assistantExpandedContent {
@extend .pageExpandedContent;
}
.assistantHeader {
@extend .pageHeader;
}
:global {
.userLink {
color: #000;
text-decoration: none;
transition: color .2s;
&:hover {
color: #1677ff; // 悬停颜色
}
}
}
Loading…
Cancel
Save