This commit is contained in:
mmc
2026-05-06 16:49:07 +08:00
parent 8413284b45
commit de1998a9a8
6 changed files with 135 additions and 52 deletions

View File

@@ -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>

View File

@@ -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) => (

View File

@@ -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,

View File

@@ -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>
}
/>

View File

@@ -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
View 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);