权限
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { Button, Popconfirm } from 'antd';
|
||||
import { DownOutlined } from '@ant-design/icons';
|
||||
import { Button, Dropdown, Popconfirm, Space } from 'antd';
|
||||
import { useUserStore } from '@/store/UserStore';
|
||||
import { GapBox } from '../GapBox';
|
||||
|
||||
@@ -7,7 +8,51 @@ export const HeaderUserInfo: React.FC = () => {
|
||||
|
||||
return (
|
||||
<GapBox>
|
||||
<div>{userInfo.login_name}</div>
|
||||
{/* 用户信息 Dropdown */}
|
||||
<Dropdown
|
||||
trigger={['click']}
|
||||
placement='bottomRight'
|
||||
arrow
|
||||
menu={{
|
||||
items: [
|
||||
{
|
||||
key: 'user-info',
|
||||
disabled: true, // 只展示,不可操作
|
||||
label: (
|
||||
<Space size={8} style={{ color: 'rgba(0,0,0,0.88)' }}>
|
||||
<span>{userInfo.username}</span>
|
||||
<span>({userInfo.nickname})</span>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
],
|
||||
}}
|
||||
>
|
||||
<div style={{ cursor: 'pointer' }}>
|
||||
<Space size={4}>
|
||||
<span>欢迎您,</span>
|
||||
<span
|
||||
style={{
|
||||
maxWidth: 120,
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
overflow: 'hidden',
|
||||
}}
|
||||
>
|
||||
{userInfo.username}
|
||||
</span>
|
||||
<DownOutlined
|
||||
style={{
|
||||
fontSize: 10,
|
||||
marginTop: 2,
|
||||
color: '#666',
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</div>
|
||||
</Dropdown>
|
||||
|
||||
{/* 退出登录 */}
|
||||
<Popconfirm
|
||||
title='确定要退出登录吗?'
|
||||
onConfirm={() => {
|
||||
|
||||
@@ -19,23 +19,23 @@ interface MenuDataItem {
|
||||
const userMenu: MenuDataItem = {
|
||||
name: '用户管理',
|
||||
icon: <UserOutlined style={iconStyle} />,
|
||||
children: [{ name: '用户信息', path: '/user/list', auth: '' }], //SF_ERP_USER_VIEW
|
||||
children: [{ name: '用户信息', path: '/user/list', auth: 'SF_ADMIN_USER_VIEW' }],
|
||||
};
|
||||
const companyMenu: MenuDataItem = {
|
||||
name: '企业管理',
|
||||
icon: <TeamOutlined style={iconStyle} />,
|
||||
children: [{ name: '企业信息', path: '/company/list', auth: '' }], //SF_ERP_COMPANY_VIEW
|
||||
children: [{ name: '企业信息', path: '/company/list', auth: 'SF_ADMIN_COMPANY_VIEW' }],
|
||||
};
|
||||
const authMenu: MenuDataItem = {
|
||||
name: '权限管理',
|
||||
icon: <BarsOutlined style={iconStyle} />,
|
||||
children: [
|
||||
{ name: '管理员信息', path: '/staff/list', auth: '' }, //SF_ERP_ADMIN_VIEW
|
||||
{ name: '组织架构', path: '/staff/dep', auth: '' }, //SF_ERP_DEPART_VIEW
|
||||
{ name: '岗位角色', path: '/staff/group', auth: '' }, //SF_ERP_GROUP_VIEW
|
||||
{ name: '我的权限', path: '/staff/my', auth: '' }, //SF_MY_RIGHT_VIEW
|
||||
{ name: '登录日志', path: '/staff/login', auth: '' }, //SF_LOGIN_LOG_VIEW
|
||||
{ name: '操作日志', path: '/staff/sys', auth: '' }, //SF_OPERATE_LOG_VIEW
|
||||
{ name: '管理员信息', path: '/staff/list', auth: 'SF_ADMIN_ADMIN_VIEW' },
|
||||
{ name: '组织架构', path: '/staff/dep', auth: 'SF_ADMIN_DEPART_VIEW' },
|
||||
{ name: '岗位角色', path: '/staff/group', auth: 'SF_ADMIN_GROUP_VIEW' },
|
||||
{ name: '我的权限', path: '/staff/auth', auth: 'SF_ADMIN_AUTH_VIEW' },
|
||||
{ name: '登录日志', path: '/staff/login', auth: 'SF_LOGIN_LOG_VIEW' },
|
||||
{ name: '操作日志', path: '/staff/sys', auth: 'SF_OPERATE_LOG_VIEW' },
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import ErrorPage from '@/pages/Error';
|
||||
import Index from '@/pages/Index';
|
||||
import Login from '@/pages/Record/Login';
|
||||
import Sys from '@/pages/Record/Sys';
|
||||
import Auth from '@/pages/Staff/Auth';
|
||||
import Dep from '@/pages/Staff/Dep';
|
||||
import Grp from '@/pages/Staff/Grp';
|
||||
import StaffList from '@/pages/Staff/List';
|
||||
@@ -45,6 +46,7 @@ export const routes: IRouteItem[] = [
|
||||
{ path: '/list', Component: StaffList },
|
||||
{ path: '/dep', Component: Dep },
|
||||
{ path: '/group', Component: Grp },
|
||||
{ path: '/auth', Component: Auth },
|
||||
{ path: '/login', Component: Login },
|
||||
{ path: '/sys', Component: Sys },
|
||||
],
|
||||
|
||||
@@ -25,10 +25,9 @@ const AppLayout = () => {
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
loginState().then((res) => {
|
||||
// console.log(res);
|
||||
userStore.updateUser(toObject(res.user_info));
|
||||
authStore.updateAuth(toObject(res.auth_info) as any);
|
||||
localStorage.setItem('admin_user_id', res?.user_info?.user_id);
|
||||
userStore.updateUser(toObject(res.admin));
|
||||
authStore.updateAuth(toObject(res.auth) as any);
|
||||
localStorage.setItem('admin_id', res?.admin?.admin_id);
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -105,7 +105,6 @@ const CompanyListForm: React.FC = () => {
|
||||
function page(curr: number) {
|
||||
if (!userLoading) {
|
||||
params.curr_page = curr;
|
||||
console.log(params);
|
||||
userRequest(stringify(params));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,21 +5,14 @@ import loginBg from '@/assets/loginBg.jpg';
|
||||
import { FormItemPlugin, FormPlugin } from '@/components/FormPlugin';
|
||||
import { DefaultERPName } from '@/configs/config';
|
||||
import { AdminServices } from '@/services/AdminServices';
|
||||
import { type IAuth, useAuthStore } from '@/store/AuthStore';
|
||||
import { useUserStore } from '@/store/UserStore';
|
||||
import { toObject } from '@/utils/common';
|
||||
import { notificationEventBus } from '@/utils/EventBus';
|
||||
import { useRequest } from '@/utils/useRequest';
|
||||
|
||||
const Login = () => {
|
||||
const user = useUserStore();
|
||||
const auth = useAuthStore();
|
||||
const [userInfo, setUserInfo] = useState({ username: 'admin', password: '123456', login_type: 1 });
|
||||
const { request, loading } = useRequest(AdminServices.login, {
|
||||
onSuccessCodeZero: (res) => {
|
||||
onSuccessCodeZero: () => {
|
||||
notificationEventBus.emit({ description: '登录成功' });
|
||||
user.updateUser(res.admin);
|
||||
auth.updateAuth(toObject(res.auth) as IAuth);
|
||||
location.href = '#/';
|
||||
},
|
||||
});
|
||||
|
||||
137
src/pages/Staff/Auth/index.tsx
Normal file
137
src/pages/Staff/Auth/index.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
import { Tree } from 'antd';
|
||||
import type React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import PageContainerPlugin from '@/components/PageContainer/PageContainerPlugin';
|
||||
import { AdminServices } from '@/services/AdminServices';
|
||||
import { useAuthStore } from '@/store/AuthStore';
|
||||
import { useRequest } from '@/utils/useRequest';
|
||||
|
||||
/** 登录管理员权限列表页面 */
|
||||
const AuthForm: React.FC = () => {
|
||||
const auth = useAuthStore().auth;
|
||||
|
||||
const [menuTree, setMenuTree] = useState<any[]>([]);
|
||||
const [checkedKeys, setCheckedKeys] = useState<React.Key[]>([]);
|
||||
const [expandedKeys, setExpandedKeys] = useState<React.Key[]>([]);
|
||||
|
||||
/** 将后端数据转换为 Tree 节点 */
|
||||
const transformToTreeNodes = (menus: any[]): any[] => {
|
||||
return menus.map((menu) => {
|
||||
const childrenNodes: any[] = [];
|
||||
|
||||
// 子菜单
|
||||
if (menu.children?.length) {
|
||||
menu.children.forEach((child: any) => {
|
||||
const childNodes: any[] = [];
|
||||
|
||||
// 子菜单下的子菜单功能
|
||||
if (child.children?.length) {
|
||||
child.children.forEach((func: any) => {
|
||||
childNodes.push({
|
||||
title: func.function_ch_name,
|
||||
key: `func_${func.function_id}`,
|
||||
isLeaf: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 子菜单自己的功能
|
||||
if (child.functions?.length) {
|
||||
child.functions.forEach((func: any) => {
|
||||
childNodes.push({
|
||||
title: func.function_ch_name,
|
||||
key: `func_${func.function_id}`,
|
||||
isLeaf: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
childrenNodes.push({
|
||||
title: child.menu_ch_name,
|
||||
key: `menu_${child.menu_id}`,
|
||||
children: childNodes.length ? childNodes : undefined,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// 顶级菜单功能
|
||||
if (menu.functions?.length) {
|
||||
menu.functions.forEach((func: any) => {
|
||||
childrenNodes.push({
|
||||
title: func.function_ch_name,
|
||||
key: `func_${func.function_id}`,
|
||||
isLeaf: true,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
title: menu.menu_ch_name,
|
||||
key: `menu_${menu.menu_id}`,
|
||||
children: childrenNodes.length ? childrenNodes : undefined,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
/** 获取 Tree 所有 key(用于默认全展开) */
|
||||
const getAllTreeKeys = (nodes: any[]): React.Key[] => {
|
||||
const keys: React.Key[] = [];
|
||||
|
||||
const loop = (list: any[]) => {
|
||||
list.forEach((item) => {
|
||||
keys.push(item.key);
|
||||
if (item.children) {
|
||||
loop(item.children);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
loop(nodes);
|
||||
return keys;
|
||||
};
|
||||
|
||||
/** 获取当前管理员权限 */
|
||||
const { loading: listLoading, request: listRequest } = useRequest(AdminServices.auth, {
|
||||
onSuccessCodeZero: (res) => {
|
||||
const tree = transformToTreeNodes(res.rule);
|
||||
setMenuTree(tree);
|
||||
|
||||
setExpandedKeys(getAllTreeKeys(tree)); // ⭐ 关键:全展开
|
||||
|
||||
// 如果后端返回的是 function_id 列表,这里可以顺便做回显
|
||||
if (res?.auth) {
|
||||
//const keys = res.auth.split(',').map((id: string) => `func_${id}`);
|
||||
const keys = res.auth.map((id: number) => `func_${id}`);
|
||||
setCheckedKeys(keys);
|
||||
} else {
|
||||
setCheckedKeys([]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!listLoading) {
|
||||
listRequest();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Tree
|
||||
checkable
|
||||
checkStrictly={false} // 父子联动
|
||||
treeData={menuTree}
|
||||
checkedKeys={checkedKeys}
|
||||
expandedKeys={expandedKeys}
|
||||
onExpand={(keys) => setExpandedKeys(keys)}
|
||||
onCheck={() => {}} // 只读
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const Auth = () => (
|
||||
<PageContainerPlugin breadcrumb={['权限管理', '我的权限']}>
|
||||
<AuthForm />
|
||||
</PageContainerPlugin>
|
||||
);
|
||||
|
||||
export default Auth;
|
||||
@@ -61,6 +61,7 @@ const GrpListForm: React.FC = () => {
|
||||
<GapBox>
|
||||
{item?.group_id != 1 && (
|
||||
<>
|
||||
{auth.SF_ADMIN_GROUP_EDIT && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -69,8 +70,10 @@ const GrpListForm: React.FC = () => {
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{auth.SF_ADMIN_GROUP_DEL && (
|
||||
<Popconfirm
|
||||
placement='bottom'
|
||||
placement='top'
|
||||
title='确认删除该岗位角色吗?'
|
||||
onConfirm={() => {
|
||||
deleteAdminGroupRequest(stringify({ group_id: item.group_id }));
|
||||
@@ -78,6 +81,7 @@ const GrpListForm: React.FC = () => {
|
||||
>
|
||||
<Button danger>删除</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</GapBox>
|
||||
@@ -190,6 +194,7 @@ const GrpListForm: React.FC = () => {
|
||||
|
||||
<GapBox style={{ marginBottom: 12, justifyContent: 'space-between' }}>
|
||||
<GapBox>
|
||||
{auth.SF_ADMIN_GROUP_ADD && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -198,6 +203,7 @@ const GrpListForm: React.FC = () => {
|
||||
>
|
||||
新增
|
||||
</Button>
|
||||
)}
|
||||
</GapBox>
|
||||
<HeaderPagination
|
||||
style={{ marginBottom: 0, marginRight: 12 }}
|
||||
|
||||
@@ -67,6 +67,7 @@ const AdminListForm: React.FC = () => {
|
||||
<GapBox>
|
||||
{item?.admin_id != 1 && (
|
||||
<>
|
||||
{auth.SF_ADMIN_ADMIN_EDIT && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -75,8 +76,10 @@ const AdminListForm: React.FC = () => {
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{auth.SF_ADMIN_ADMIN_DEL && (
|
||||
<Popconfirm
|
||||
placement='bottom'
|
||||
placement='top'
|
||||
title='确认删除该管理员吗?'
|
||||
onConfirm={() => {
|
||||
deleteAdminRequest(stringify({ admin_id: item.admin_id }));
|
||||
@@ -84,6 +87,7 @@ const AdminListForm: React.FC = () => {
|
||||
>
|
||||
<Button danger>删除</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</GapBox>
|
||||
@@ -107,7 +111,6 @@ const AdminListForm: React.FC = () => {
|
||||
function page(curr: number) {
|
||||
if (!listLoading) {
|
||||
params.curr_page = curr;
|
||||
console.log(params);
|
||||
listRequest(stringify(params));
|
||||
}
|
||||
}
|
||||
@@ -219,6 +222,7 @@ const AdminListForm: React.FC = () => {
|
||||
|
||||
<GapBox style={{ marginBottom: 12, justifyContent: 'space-between' }}>
|
||||
<GapBox>
|
||||
{auth.SF_ADMIN_ADMIN_ADD && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -227,6 +231,7 @@ const AdminListForm: React.FC = () => {
|
||||
>
|
||||
新增
|
||||
</Button>
|
||||
)}
|
||||
</GapBox>
|
||||
<HeaderPagination
|
||||
style={{ marginBottom: 0, marginRight: 12 }}
|
||||
|
||||
@@ -63,6 +63,7 @@ const DepListForm: React.FC = () => {
|
||||
<GapBox>
|
||||
{item?.admin_id != 1 && (
|
||||
<>
|
||||
{auth.SF_ADMIN_DEPART_EDIT && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -71,8 +72,10 @@ const DepListForm: React.FC = () => {
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
)}
|
||||
{auth.SF_ADMIN_DEPART_DEL && (
|
||||
<Popconfirm
|
||||
placement='bottom'
|
||||
placement='top'
|
||||
title='确认删除该组织架构吗?'
|
||||
onConfirm={() => {
|
||||
deleteAdminDepartmentRequest(stringify({ department_id: item.department_id }));
|
||||
@@ -80,6 +83,7 @@ const DepListForm: React.FC = () => {
|
||||
>
|
||||
<Button danger>删除</Button>
|
||||
</Popconfirm>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</GapBox>
|
||||
@@ -99,7 +103,6 @@ const DepListForm: React.FC = () => {
|
||||
function page(curr: number) {
|
||||
if (!listLoading) {
|
||||
params.curr_page = curr;
|
||||
console.log(params);
|
||||
listRequest(stringify(params));
|
||||
}
|
||||
}
|
||||
@@ -193,6 +196,7 @@ const DepListForm: React.FC = () => {
|
||||
|
||||
<GapBox style={{ marginBottom: 12, justifyContent: 'space-between' }}>
|
||||
<GapBox>
|
||||
{auth.SF_ADMIN_DEPART_ADD && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -201,6 +205,7 @@ const DepListForm: React.FC = () => {
|
||||
>
|
||||
新增
|
||||
</Button>
|
||||
)}
|
||||
</GapBox>
|
||||
<HeaderPagination
|
||||
style={{ marginBottom: 0, marginRight: 12 }}
|
||||
|
||||
@@ -16,6 +16,7 @@ import CompanySelect from '@/pages/Company/List/components/CompanySelect';
|
||||
import { type IUserEditModalType, UserEditModal } from '@/pages/User/List/components/UserEditModal';
|
||||
import { UserServices } from '@/services/UserServices';
|
||||
import { useAuthStore } from '@/store/AuthStore';
|
||||
import { useUserStore } from '@/store/UserStore';
|
||||
import { tableFixedByPhone, toArray } from '@/utils/common';
|
||||
import { useRequest } from '@/utils/useRequest';
|
||||
|
||||
@@ -34,8 +35,10 @@ type IParams = IParamsBase & {
|
||||
|
||||
/** 用户列表页面 */
|
||||
const UserListForm: React.FC = () => {
|
||||
const user = useUserStore().user;
|
||||
console.log('user', user);
|
||||
const auth = useAuthStore().auth;
|
||||
|
||||
console.log('auth', auth);
|
||||
const [ajaxData, setAjaxData] = useState<IAjaxData>({ count: 0, data: [] });
|
||||
const [showMoreSearch, setShowMoreSearch] = useState(false);
|
||||
const UserEditModalRef = useRef<IUserEditModalType>(null);
|
||||
@@ -59,15 +62,7 @@ const UserListForm: React.FC = () => {
|
||||
fixed: tableFixedByPhone('left'),
|
||||
render: (_, item) => (
|
||||
<GapBox>
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
UserEditModalRef.current?.show(item);
|
||||
}}
|
||||
>
|
||||
编辑
|
||||
</Button>
|
||||
{auth.SF_ERP_USER_EDIT && (
|
||||
{auth.SF_ADMIN_USER_EDIT && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -80,10 +75,10 @@ const UserListForm: React.FC = () => {
|
||||
</GapBox>
|
||||
),
|
||||
},
|
||||
{ title: '用户名', dataIndex: 'login_name', width: 120 },
|
||||
{ title: '企业', dataIndex: 'company_name', width: 120 },
|
||||
{ title: '类型', dataIndex: 'staff_type', width: 60, render: (value) => staffType[value] },
|
||||
{ title: '用户名', dataIndex: 'login_name', width: 120 },
|
||||
{ title: '昵称', dataIndex: 'nick_name', width: 120 },
|
||||
{ title: '类型', dataIndex: 'staff_type', width: 60, render: (value) => staffType[value] },
|
||||
{ title: '手机', dataIndex: 'user_phone', width: 120 },
|
||||
{ title: '性别', dataIndex: 'user_sex', width: 60, render: (value) => userSex[value] },
|
||||
{ title: '状态', dataIndex: 'state', width: 60, ellipsis: true, render: (value) => userState[value] },
|
||||
@@ -103,7 +98,6 @@ const UserListForm: React.FC = () => {
|
||||
function page(curr: number) {
|
||||
if (!userLoading) {
|
||||
params.curr_page = curr;
|
||||
console.log(params);
|
||||
userRequest(stringify(params));
|
||||
}
|
||||
}
|
||||
@@ -209,6 +203,7 @@ const UserListForm: React.FC = () => {
|
||||
|
||||
<GapBox style={{ marginBottom: 12, justifyContent: 'space-between' }}>
|
||||
<GapBox>
|
||||
{auth.SF_ADMIN_USER_ADD && (
|
||||
<Button
|
||||
type='primary'
|
||||
onClick={() => {
|
||||
@@ -217,6 +212,7 @@ const UserListForm: React.FC = () => {
|
||||
>
|
||||
新增
|
||||
</Button>
|
||||
)}
|
||||
</GapBox>
|
||||
<HeaderPagination
|
||||
style={{ marginBottom: 0, marginRight: 12 }}
|
||||
|
||||
@@ -10,4 +10,6 @@ export const AdminServices = {
|
||||
add: '/Admin/add',
|
||||
edit: '/Admin/edit',
|
||||
del: '/Admin/del',
|
||||
/** 登录管理员权限列表 */
|
||||
auth: '/Admin/auth',
|
||||
} as const;
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
export type UserInfo = {
|
||||
login_name?: string;
|
||||
logo?: string;
|
||||
last_login_time?: string;
|
||||
nick_name?: string;
|
||||
state?: number;
|
||||
user_id?: number;
|
||||
user_sex?: number;
|
||||
user_phone?: string;
|
||||
visit_times?: string;
|
||||
admin_id?: number;
|
||||
username?: string;
|
||||
nickname?: string;
|
||||
avatar?: string;
|
||||
status?: number;
|
||||
email?: string;
|
||||
mobile?: string;
|
||||
create_date?: string;
|
||||
logoKey?: number;
|
||||
wx_head_img?: string;
|
||||
wx_nick_name?: string;
|
||||
wx_open_id?: string;
|
||||
self_account?: number;
|
||||
department_id?: number;
|
||||
};
|
||||
|
||||
export type CompanyInfo = {
|
||||
|
||||
Reference in New Issue
Block a user