修改
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Outlet, useNavigate, useLocation } from 'react-router-dom';
|
||||
import {
|
||||
Layout, Menu, Button, Space, ConfigProvider, theme
|
||||
Layout, Menu, Button, Space, ConfigProvider, theme, Select
|
||||
} from 'antd';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import {
|
||||
@@ -13,37 +13,68 @@ import logo from '../assets/logo.png';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { RootState, useAppDispatch } from '../store';
|
||||
import { logout } from '../store/userSlice';
|
||||
import { setCurrentStation, clearStation } from '../store/stationSlice'; // 👈 引入
|
||||
import { getMenuList } from '../api/mune';
|
||||
import { getStationList } from '../api/stationManage';
|
||||
|
||||
const { Header, Sider, Content } = Layout;
|
||||
|
||||
export default function AppLayout() {
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
const [time, setTime] = useState(new Date().toLocaleString());
|
||||
const [menuList, setMenuList] = useState([]); // 一级菜单列表
|
||||
const [menuList, setMenuList] = useState([]);
|
||||
const [stationList, setStationList] = useState([]);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const { userInfo } = useSelector((state: RootState) => state.user);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// ======================
|
||||
// 只取一级菜单(parentId=0)
|
||||
// ======================
|
||||
// 全局用户信息
|
||||
const { userInfo } = useSelector((state: RootState) => state.user);
|
||||
// 全局场站信息
|
||||
const { currentStation, stationId } = useSelector((state: RootState) => state.station);
|
||||
|
||||
// 获取场站列表
|
||||
const getStationData = () => {
|
||||
const params = {
|
||||
pageNum: 1,
|
||||
pageSize: 9999,
|
||||
orgId: userInfo?.orgId,
|
||||
};
|
||||
getStationList(params).then(res => {
|
||||
if (res.code === 200) {
|
||||
const list = res.rows || [];
|
||||
setStationList(list);
|
||||
|
||||
// 如果没有选中任何场站,默认选第一个
|
||||
if (!currentStation && list.length > 0) {
|
||||
dispatch(setCurrentStation(list[0]));
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// 切换场站
|
||||
const handleStationChange = (id: number) => {
|
||||
const station = stationList.find(s => s.id === id);
|
||||
if (station) {
|
||||
dispatch(setCurrentStation(station)); // 👈 存全局
|
||||
}
|
||||
};
|
||||
|
||||
// 获取菜单
|
||||
const getMenu = () => {
|
||||
const data = { pageNum: 1, pageSize: 10000 };
|
||||
getMenuList(data).then(res => {
|
||||
if (res.code == 200) {
|
||||
const rawList = res.rows || [];
|
||||
// 只保留 parentId=0 的一级菜单
|
||||
const topMenus = rawList.filter(item => item.parentId === 0);
|
||||
setMenuList(topMenus);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// ======================
|
||||
// 菜单图标映射
|
||||
// ======================
|
||||
// 图标映射
|
||||
const getIcon = (path) => {
|
||||
if (path.includes('overview')) return <DashboardOutlined />;
|
||||
if (path.includes('device')) return <ExperimentOutlined />;
|
||||
@@ -55,25 +86,26 @@ export default function AppLayout() {
|
||||
return <AppstoreOutlined />;
|
||||
};
|
||||
|
||||
// ======================
|
||||
// 构造 antd menu items(纯平铺,无children)
|
||||
// ======================
|
||||
// 菜单
|
||||
const menuItems = menuList.map(item => ({
|
||||
key: item.path || `/menu/${item.menuId}`,
|
||||
icon: getIcon(item.path),
|
||||
label: item.menuName,
|
||||
}));
|
||||
|
||||
// 退出登录时清空场站
|
||||
const handleLogout = async () => {
|
||||
await dispatch(logout());
|
||||
dispatch(clearStation()); // 👈 清空
|
||||
navigate('/login', { replace: true });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => setTime(new Date().toLocaleString()), 1000);
|
||||
getMenu();
|
||||
getStationData();
|
||||
return () => clearInterval(timer);
|
||||
}, []);
|
||||
|
||||
const handleLogout = async () => {
|
||||
await dispatch(logout());
|
||||
navigate('/login', { replace: true });
|
||||
};
|
||||
}, [userInfo]);
|
||||
|
||||
return (
|
||||
<ConfigProvider
|
||||
@@ -97,13 +129,29 @@ export default function AppLayout() {
|
||||
justifyContent: 'space-between',
|
||||
padding: '0 16px'
|
||||
}}>
|
||||
<Space size="small">
|
||||
<img src={logo} alt="Logo" style={{ width: 24, height: 24 }} />
|
||||
{!collapsed && (
|
||||
<span style={{ fontWeight: 'bold', fontSize: 16, color: '#fff' }}>
|
||||
光伏电站智能监控与运维系统
|
||||
</span>
|
||||
)}
|
||||
<Space size="large" style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Space size="small">
|
||||
<img src={logo} alt="Logo" style={{ width: 24, height: 24 }} />
|
||||
{!collapsed && (
|
||||
<span style={{ fontWeight: 'bold', fontSize: 16, color: '#fff' }}>
|
||||
光伏电站智能监控与运维系统
|
||||
</span>
|
||||
)}
|
||||
</Space>
|
||||
|
||||
{/* 全局场站选择器 */}
|
||||
<Select
|
||||
value={stationId}
|
||||
placeholder="请选择电站"
|
||||
onChange={handleStationChange}
|
||||
options={stationList.map(s => ({ label: s.siteName, value: s.id }))}
|
||||
style={{
|
||||
width: 180,
|
||||
backgroundColor: '#0837a8',
|
||||
color: '#fff',
|
||||
border: 'none',
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
|
||||
<Space size="middle">
|
||||
@@ -115,11 +163,7 @@ export default function AppLayout() {
|
||||
</Space>
|
||||
</Header>
|
||||
|
||||
<Layout style={{
|
||||
height: 'calc(100vh - 50px)',
|
||||
overflow: 'hidden',
|
||||
background: '#fff'
|
||||
}}>
|
||||
<Layout style={{ height: 'calc(100vh - 50px)', overflow: 'hidden', background: '#fff' }}>
|
||||
<Sider
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
@@ -128,7 +172,6 @@ export default function AppLayout() {
|
||||
theme="light"
|
||||
style={{ borderRight: '1px solid #e5e7eb' }}
|
||||
>
|
||||
{/* 纯平铺一级菜单 */}
|
||||
<Menu
|
||||
mode="inline"
|
||||
theme="light"
|
||||
@@ -138,11 +181,7 @@ export default function AppLayout() {
|
||||
/>
|
||||
</Sider>
|
||||
|
||||
<Content style={{
|
||||
background: '#f4f7f9',
|
||||
overflowY: 'auto',
|
||||
padding: '16px'
|
||||
}}>
|
||||
<Content style={{ background: '#f4f7f9', overflowY: 'auto', padding: '16px' }}>
|
||||
<Outlet />
|
||||
</Content>
|
||||
</Layout>
|
||||
|
||||
@@ -125,15 +125,15 @@ export default function Organization() {
|
||||
{ title: '负责人', dataIndex: 'manager' },
|
||||
{ title: '联系电话', dataIndex: 'phone' },
|
||||
{ title: '邮箱', dataIndex: 'email' },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
render: (s) => (
|
||||
<span className={s == 1 ? 'text-green-600' : 'text-red-600'}>
|
||||
{s == 1 ? '正常' : '禁用'}
|
||||
</span>
|
||||
)
|
||||
},
|
||||
//{
|
||||
// title: '状态',
|
||||
// dataIndex: 'status',
|
||||
// render: (s) => (
|
||||
// <span className={s == 1 ? 'text-green-600' : 'text-red-600'}>
|
||||
// {s == 1 ? '正常' : '禁用'}
|
||||
// </span>
|
||||
// )
|
||||
//},
|
||||
{
|
||||
title: '操作',
|
||||
render: (_, r) => (
|
||||
|
||||
@@ -206,11 +206,11 @@ export default function StationManage() {
|
||||
}
|
||||
},
|
||||
{ title: '地址', dataIndex: 'address' },
|
||||
{
|
||||
title: '状态',
|
||||
dataIndex: 'status',
|
||||
render: s => s === 1 ? <Tag color="green">启用</Tag> : <Tag color="red">停用</Tag>
|
||||
},
|
||||
//{
|
||||
// title: '状态',
|
||||
// dataIndex: 'status',
|
||||
// render: s => s === 1 ? <Tag color="green">启用</Tag> : <Tag color="red">停用</Tag>
|
||||
//},
|
||||
{
|
||||
title: '操作',
|
||||
width: 400,
|
||||
|
||||
@@ -513,7 +513,7 @@ export default function UserRolePage() {
|
||||
<Space direction="vertical" size={2}>
|
||||
<Text type="secondary">权限:{r.roleKey}</Text>
|
||||
<Text type="secondary">等级:{r.roleLevel || '-'}</Text>
|
||||
{r.roleKey == "admin1" && <Tag color="red">超级管理员</Tag>}
|
||||
{/*{r.roleKey == "admin1" && <Tag color="red">超级管理员</Tag>}*/}
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -3,10 +3,12 @@ import { useDispatch } from 'react-redux';
|
||||
|
||||
// 👇 保留 import,但是把类型定义放到 store 后面
|
||||
import userReducer from './userSlice';
|
||||
import stationReducer from './stationSlice'; // 👈 加这个
|
||||
|
||||
export const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
station: stationReducer, // 👈 加这个
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
42
src/store/stationSlice.ts
Normal file
42
src/store/stationSlice.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { createSlice } from '@reduxjs/toolkit';
|
||||
|
||||
// 从 localStorage 加载上次选中的场站
|
||||
const loadStationFromStorage = () => {
|
||||
try {
|
||||
const station = localStorage.getItem('currentStation');
|
||||
return station ? JSON.parse(station) : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
currentStation: loadStationFromStorage(), // 当前选中场站(完整对象)
|
||||
stationId: loadStationFromStorage()?.id || null, // 方便直接用 id
|
||||
};
|
||||
|
||||
const stationSlice = createSlice({
|
||||
name: 'station',
|
||||
initialState,
|
||||
reducers: {
|
||||
// 设置当前场站
|
||||
setCurrentStation: (state, action) => {
|
||||
state.currentStation = action.payload;
|
||||
state.stationId = action.payload?.id || null;
|
||||
localStorage.setItem('currentStation', JSON.stringify(action.payload));
|
||||
},
|
||||
// 清空场站(退出登录时用)
|
||||
clearStation: (state) => {
|
||||
state.currentStation = null;
|
||||
state.stationId = null;
|
||||
localStorage.removeItem('currentStation');
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { setCurrentStation, clearStation } = stationSlice.actions;
|
||||
export default stationSlice.reducer;
|
||||
|
||||
|
||||
//使用const { currentStation, stationId } = useSelector((state: RootState) => state.station);
|
||||
|
||||
Reference in New Issue
Block a user