You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
22 KiB
JavaScript

1 month ago
import React, { useState, useEffect } from 'react'
2 months ago
import { history, Outlet, useLocation, matchRoutes, useModel } from '@umijs/max'
import { Menu, Tabs, Select } from 'antd'
2 months ago
import './SystemContentList.less'
import { formatRoute, getDefaultRoute } from '@/utils/routeUtils'
import styles from './TopNavBar.less'
import { Row, Col, Avatar, Dropdown, Button } from 'antd'
import { userInfo } from '@/utils/globalCommon'
import { HomeOutlined, LogoutOutlined, AppstoreOutlined, UserOutlined, SettingOutlined, DatabaseOutlined, FileTextOutlined, LockOutlined, AreaChartOutlined, CaretDownOutlined, BellOutlined, SearchOutlined, QuestionCircleOutlined } from '@ant-design/icons'
2 months ago
import { getPageQuery } from '@/utils/utils'
1 month ago
import menuTitle from '@/assets/img/智能管控平台.svg'
import menuTitle1 from '@/assets/img/智能管控平台-1.svg'
import fireHydrant from '@/assets/img/fireHydrant.svg'
import fireHydrant1 from '@/assets/img/fireHydrant1.svg'
import riskClassification from '@/assets/img/riskclassification.svg'
import trouble from '@/assets/img/trouble.svg'
import book from '@/assets/img/book.svg'
import danger from '@/assets/img/danger.svg'
import danger1 from '@/assets/img/danger1.svg'
import license from '@/assets/img/license.svg'
import licenseLight from '@/assets/img/licenseLight.svg'
import people from '@/assets/img/people.svg'
import risk from '@/assets/img/risk.svg'
import safeEducationLight from '@/assets/img/safeEducationLight.svg'
import bookDark from '@/assets/img/bookDark.svg'
import bookLight from '@/assets/img/bookLight.svg'
import personnelPosition2 from '@/assets/img/personnelPosition2.svg'
import { CustomBreadcrumb } from '@/components/GlobalComponent'
2 months ago
1 month ago
// 自定义菜单项渲染组件,支持根据激活状态显示不同图片
const CustomMenuItem = ({ item, selectedKeys }) => {
const isActive = selectedKeys.includes(item.key);
// 为每个菜单项定义激活状态的图片
// 如果没有专门的激活状态图片,则使用默认图片
const getActiveIcon = (baseIcon) => {
// 这里可以根据需要为每个图标定义对应的激活状态图片
// 目前暂时使用相同的图片,用户可以根据实际情况替换
return baseIcon;
};
const renderIcon = () => {
if (item.icon && typeof item.icon === 'object' && item.icon.props && item.icon.props.src) {
const iconSrc = isActive ? getActiveIcon(item.icon.props.src) : item.icon.props.src;
return <img
src={iconSrc}
alt={item.icon.props.alt || 'menu icon'}
style={item.icon.props.style || { width: '16px', height: '16px' }}
/>
}
return item.icon;
};
const renderMenuItem = (menuItem) => ({
...menuItem,
icon: renderIcon(),
children: menuItem.children?.map(child => renderMenuItem(child))
});
return renderMenuItem(item);
};
2 months ago
const SystemContentList = (props) => {
const dynamicRoute = window.dynamicRoute
console.log(dynamicRoute)
const location = useLocation()
const pathName = location.pathname
const [openKey, setOpenKey] = useState([])
const [selectedKey, setSelectedKey] = useState([])
const [menuItems, setMenuItems] = useState([])
2 months ago
const [systemType, setSystemType] = useState('安全管理系统')
const [isMenuCollapsed, setIsMenuCollapsed] = useState(false); // 添加菜单收缩状态
2 months ago
let defaultKey = ''
useEffect(() => {
1 month ago
console.log('dynamicRoute structure:', dynamicRoute)
2 months ago
if (!dynamicRoute || dynamicRoute?.length === 0) return
let newList = []
let routes = []
if (dynamicRoute?.length) {
let tempRoute = dynamicRoute?.filter(item => pathName.indexOf(item.key) !== -1) ?? []
newList = formatRoute(tempRoute[0]?.children)
routes = formatRoute(tempRoute[0]?.children, true)
defaultKey = getDefaultRoute(routes)
const mathRoute = matchRoutes(routes, pathName)
setRouteActive({ key: mathRoute?.length ? pathName : defaultKey }, routes)
}
setMenuItems(newList)
const fixedMenuItems = [
{
"path": "/topnavbar00/hrefficiency/basicinformation",
icon: <img src={fireHydrant1} alt="安全管理基础信息" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/basicinformation",
"label": "安全管理基础信息"
},
{
1 month ago
"path": "/topnavbar00/hrefficiency/safeMajorHazard",
icon: <img src={danger} alt="重大危险源管理" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/safeMajorHazard",
"label": "重大危险源管理"
},
{
"path": "/topnavbar00/hrefficiency/riskclassification",
icon: <img src={risk} alt="风险分级管控" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/riskclassification",
"label": "风险分级管控"
},
{
"path": "/topnavbar00/hrefficiency/hiddentrouble",
icon: <img src={risk} alt="工时仪表盘" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/hiddentrouble",
"label": "隐患排查"
},
{
"path": "/topnavbar00/hrefficiency/safetraining",
icon: <img src={bookDark} alt="安全教育培训" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/safetraining",
"label": "安全教育培训"
},
{
"path": "/topnavbar00/hrefficiency/personnellocation",
icon: <img src={people} alt="人员定位" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/personnellocation",
"label": "人员定位"
},
{
"path": "/topnavbar00/hrefficiency/specialoperationpermit",
icon: <img src={license} alt="特殊作业许可" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/specialoperationpermit",
"label": "特殊作业许可"
},
{
"path": "/topnavbar00/hrefficiency/system",
icon: <img src={people} alt="工时仪表盘" style={{ width: '16px', height: '16px' }} />,
"key": "/topnavbar00/hrefficiency/system",
"label": "系统管理",
"children": [
{
"path": "/topnavbar00/hrefficiency/system/systemOrganization",
"key": "/topnavbar00/hrefficiency/system/systemOrganization",
"label": "组织管理"
},
{
"path": "/topnavbar00/hrefficiency/system/systemRole",
"key": "/topnavbar00/hrefficiency/system/systemRole",
"label": "角色配置"
},
{
"path": "/topnavbar00/hrefficiency/system/systemMenu",
"key": "/topnavbar00/hrefficiency/system/systemMenu",
"label": "菜单配置"
}
]
}
]
setMenuItems(fixedMenuItems)
// 初始化默认路由
const defaultRoute = fixedMenuItems[0]?.key || ''
const mathRoute = matchRoutes(fixedMenuItems, pathName)
setRouteActive({ key: mathRoute?.length ? pathName : defaultRoute }, fixedMenuItems)
2 months ago
}, [pathName])
const setRouteActive = (value, menu) => {
const curKey = value.key
const tempMenu = menu ?? menuItems ?? []
const mathRoute = matchRoutes(tempMenu, curKey)
let openKeys = []
let selectedKeys = []
mathRoute?.map((item, index) => {
mathRoute?.length !== index + 1 && (openKeys = [...openKeys, item.pathname])
mathRoute?.length === index + 1 && (selectedKeys = [...selectedKeys, item.pathname])
})
setOpenKey(openKeys)
setSelectedKey(selectedKeys)
history.replace(curKey)
}
// 切换菜单收缩状态
const toggleMenu = () => {
setIsMenuCollapsed(!isMenuCollapsed);
};
2 months ago
const { initialState: { menu }, setInitialState } = useModel('@@initialState')
const loginOut = async () => {
// await outLogin()
const { redirect } = getPageQuery()
if (window.location.pathname !== '/login/login' && !redirect) {
history.replace({
pathname: '/login',
// search: stringify({
// redirect: window.location.href,
// }),
})
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} />
)
2 months ago
return (
<div className='pageContainer systemContent'>
<div
className='leftMenu'
style={{
width: isMenuCollapsed ? '80px' : '230px',
transition: 'width 0.3s ease',
position: 'relative', // 添加相对定位,使按钮可以相对于菜单定位
overflow: 'unset'
}}
>
<div className='menuTitle' style={{
marginBottom: '10px',
display: isMenuCollapsed ? 'none' : 'flex'
}}>
1 month ago
<img src={menuTitle} alt='menuTitle' style={{ marginTop: '20px', marginBottom: '2px', width: '172.44px', height: '51.28px' }} />
<img src={menuTitle1} alt='menuTitle1' style={{ width: '172.44px', height: '51.28px' }} />
2 months ago
</div>
<div style={{
textAlign: 'center',
marginBottom: 16,
display: isMenuCollapsed ? 'none' : 'block'
}}>
2 months ago
<Select
value={systemType}
onChange={setSystemType}
style={{
width: 192,
height: 42,
2 months ago
borderColor: '#3D81FF',
backgroundColor: '#003AA7',
borderRadius: 0,
2 months ago
color: '#fff',
fontSize: 22,
fontWeight: 600
}}
options={[
{ value: '安全管理系统', label: '安全管理系统' },
{ value: '环保管理系统', label: '环保管理系统' }
]}
dropdownStyle={{
backgroundColor: '#003AA7',
borderColor: '#3D81FF'
}}
popupClassName="custom-select-dropdown"
className="custom-select"
1 month ago
suffixIcon={<CaretDownOutlined style={{ color: '#fff', fontSize: '16px' }} />}
2 months ago
/>
</div>
<style jsx>{`
.custom-select .ant-select-selector {
height: 42px !important;
border-radius: 0 !important;
2 months ago
border-color: #3D81FF !important;
background-color: #003AA7 !important;
color: #fff !important;
fontSize: 22px !important;
fontWeight: 600 !important;
}
.custom-select .ant-select-selection-item {
color: #fff !important;
fontSize: 22px !important;
fontWeight: 600 !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
padding: 0 !important;
padding-right: 50px !important;
1 month ago
font-size: 16px !important;
font-weight: 500 !important;
2 months ago
}
.custom-select .ant-select-arrow {
opacity: 0.66 !important;
color: #fff !important;
}
.custom-select-dropdown .ant-select-item-option-selected {
background-color: #3D81FF !important;
color: #fff !important;
}
.custom-select-dropdown .ant-select-item-option-active:not(.ant-select-item-option-selected) {
background-color: rgba(61, 129, 255, 0.1) !important;
color: #fff !important;
}
.custom-select-dropdown .ant-select-item-option-content {
color: #fff !important;
font-size: 16px !important;
font-weight: 600 !important;
}
.menuToggleBtn {
position: absolute;
right: -15px;
top: 50%;
width: 30px;
height: 30px;
background: #FDFDFF;
color: #5C5C5C;
border: 1px solid #FFFFFF;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 9999; /* 增加z-index确保按钮在最上层 */
font-size: 16px;
font-weight: bold;
outline: none;
transition: all 0.3s ease;
box-shadow: 0 0 5px 3px rgba(169, 185, 255, 0.33);
}
.menuToggleBtn:hover {
border: 1px solid #3D81FF;
background: #3D81FF;
color: white;
transform: scale(1.1);
}
2 months ago
`}</style>
{/* 菜单收缩按钮 */}
<button
className="menuToggleBtn"
onClick={toggleMenu}
aria-label={isMenuCollapsed ? "展开菜单" : "收缩菜单"}
>
{isMenuCollapsed ? ">" : "<"}
</button>
2 months ago
<Menu
openKeys={openKey}
selectedKeys={selectedKey}
// 使用自定义的itemRender方法处理激活状态的图标切换
items={menuItems.map(item => {
const isActive = selectedKey.includes(item.key);
// 处理当前项的图标
let icon = item.icon;
if (icon && typeof icon === 'object' && icon.props && icon.props.src) {
let iconSrc = icon.props.src;
// 根据激活状态切换不同的图片
if (isActive) {
// 工时仪表盘激活态使用fireHydrant1
if (item.key === '/topnavbar00/hrefficiency/timesheet' && typeof fireHydrant !== 'undefined') {
iconSrc = fireHydrant;
}
// 隐患排查激活态使用danger1
else if (item.key === '/topnavbar00/hrefficiency/hiddentrouble' && typeof danger1 !== 'undefined') {
iconSrc = danger1;
}
// 激活态使用danger1
else if (item.key === '/topnavbar00/hrefficiency/staffsheet' && typeof danger1 !== 'undefined') {
iconSrc = danger1;
}
// 安全教育培训激活态使用bookLight
else if (item.key === '/topnavbar00/hrefficiency/safetraining' && typeof bookLight !== 'undefined') {
iconSrc = bookLight;
}
// 风险分级管控 菜单图标 激活态使用 riskclassification
else if (item.key === '/topnavbar00/hrefficiency/riskclassification' && typeof riskClassification !== 'undefined') {
iconSrc = riskClassification;
}
// 人员定位激活态使用personnelPosition2
else if (item.key === '/topnavbar00/hrefficiency/personnellocation' && typeof personnelPosition2 !== 'undefined') {
iconSrc = personnelPosition2;
}
// 特殊作业许可激活态使用licenseLight
else if (item.key === '/topnavbar00/hrefficiency/specialoperationpermit' && typeof licenseLight !== 'undefined') {
iconSrc = licenseLight;
}
}
icon = <img
src={iconSrc}
alt={icon.props.alt}
style={icon.props.style}
/>;
}
// 递归处理子项
const children = item.children?.map(child => {
const childIsActive = selectedKey.includes(child.key);
return { ...child };
});
return {
...item,
icon,
children,
// 根据菜单收缩状态决定是否显示标签文本
label: isMenuCollapsed ? null : item.label
};
})}
2 months ago
onClick={value => setRouteActive(value)}
onOpenChange={value => setOpenKey(value)}
mode={isMenuCollapsed ? 'vertical' : 'inline'}
2 months ago
/>
</div>
<div
className='rightContent'
style={{
width: isMenuCollapsed ? 'calc(100% - 80px)' : 'calc(100% - 230px)',
transition: 'width 0.3s ease'
}}
>
{/* <div style={{ width: '100%', backgroundColor: '#fff', marginBottom: '10px' }}> */}
<div className='tabBarHeader'>
<Row className='tabBarRow'>
{/* <Col xs={16} sm={16} md={16} lg={16} xl={16} className='tabBarLeft'>
<img src={Logo} alt='logo' className='leftLogo' />
<Menu mode='horizontal' className='leftMenu' selectedKeys={[activeKey]} items={menuItems} onClick={value => setRouteActive(value)} />
</Col> */}
<Col xs={20} sm={20} md={20} lg={20} xl={20} className='tabBarLeft'>
<CustomBreadcrumb />
</Col>
<Col xs={4} sm={4} md={4} lg={4} xl={4} className='tabBarRight'>
<Button type='text' className='tabBarRightBtn'><BellOutlined /></Button>
<Button type='text' className='tabBarRightBtn'><SearchOutlined /></Button>
<Button type='text' className='tabBarRightBtn'><QuestionCircleOutlined /></Button>
<Avatar className='tabBarRightAvaTor' src='https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201707%2F31%2F20170731021444_2YUfe.jpeg&refer=http%3A%2F%2Fb-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1669779871&t=ec025ed48a1668dee9cfa0e803b6f787' />
<span className='tabBarRightName'>{userInfo?.user_name_cn ? userInfo.user_name_cn : (userInfo?.user_name || '')}</span>
<Dropdown dropdownRender={dropDownMenu}>
<Button type='text' className='tabBarRightBtn'><SettingOutlined /></Button>
</Dropdown>
</Col>
</Row>
</div>
{/* </div> */}
<div style={{ padding: '12px', height: '100%' }}>
<div className='rightContentMain'>
<Outlet />
</div>
</div>
2 months ago
</div>
</div>
)
}
export default SystemContentList
2 months ago