历史会话

main
wangyunfei 1 day ago
parent 6a3bbea58c
commit 30e430deb4

@ -354,8 +354,9 @@ function ChatConversation() {
</div>
{/* 模型切换 */}
<Select
<div
defaultValue="智能定性"
// icon={<RobotOutlined />}
style={{
minWidth: 120, maxWidth: 200, marginRight: 8
}}
@ -367,7 +368,7 @@ function ChatConversation() {
// // { value: "Kimi Senior", label: "Kimi Senior" },
// ]}
>
</Select>
</div>
{/* 上传文件 */}
<Upload className='ds-uploading'>

@ -1,524 +0,0 @@
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

@ -228,9 +228,8 @@ const TopNavBar = (props) => {
{/* 修改当路由为智能对话页时渲染历史会话组件renderPageContent其它路由不变 */}
<div className={styles.contentMain} style={{ height: 'auto', backgroundColor: 'inherit' }}>
<Outlet />
{/* {renderPageContent('conversation', conversationConversations, conversationExpanded)} */}
</div>
{renderPageContent('conversation', conversationConversations, conversationExpanded)}
</div>
{/* 底部版权信息 */}
<div className='footerCopyright' style={{
// position: 'fixed',

Loading…
Cancel
Save