303 lines
9.1 KiB
TypeScript
303 lines
9.1 KiB
TypeScript
import { MyIcons, MyIconsType, PermissionsType, useMyState } from '@/common';
|
||
import AvatarProps from '@/common/components/layout/AvatarProps';
|
||
import { Apis } from '@/gen/Apis';
|
||
import { Link, RuntimeConfig, history, useNavigate } from '@umijs/max';
|
||
import { AutoComplete, Input, Menu, MenuProps, Select, Space } from 'antd';
|
||
import { useEffect, useState } from 'react';
|
||
import './allConfig.scss';
|
||
// import Logo from './logo.png';
|
||
interface LevelKeysProps {
|
||
key?: string;
|
||
children?: LevelKeysProps[];
|
||
}
|
||
|
||
const loopMenu = (permissions: PermissionsType[] | undefined) => {
|
||
let tree: PermissionsType[] = [];
|
||
let map: Record<number, PermissionsType> = {};
|
||
// 过滤掉Button和Tab类型的权限,这些不应该显示在菜单中
|
||
const menuPermissions = permissions?.filter(
|
||
(p) => p.type !== 'Button' && p.type !== 'Tab',
|
||
);
|
||
|
||
menuPermissions?.forEach((permission) => {
|
||
map[permission.id] = {
|
||
path: permission.path,
|
||
name: permission.name,
|
||
icon: permission.icon && MyIcons[permission.icon as MyIconsType],
|
||
label: permission.name,
|
||
key: permission.path || permission.id.toString(),
|
||
hideInMenu: false, // 已经过滤过类型,这里可以设置为false
|
||
};
|
||
});
|
||
|
||
menuPermissions?.forEach((permission) => {
|
||
let node = map[permission.id];
|
||
const parentId = permission?.parent_id;
|
||
|
||
if (parentId !== null && parentId !== undefined) {
|
||
const parentNode = map[parentId];
|
||
|
||
if (parentNode) {
|
||
// 初始化 children 如果不存在
|
||
if (!Array.isArray(parentNode.children)) {
|
||
parentNode.children = [];
|
||
}
|
||
parentNode.children.push(node);
|
||
} else {
|
||
// 父节点不存在,作为根节点处理
|
||
console.warn(
|
||
`Parent node with id ${parentId} not found for permission ${permission.id}`,
|
||
);
|
||
tree.push(node);
|
||
}
|
||
} else {
|
||
tree.push(node);
|
||
}
|
||
});
|
||
return tree?.[0]?.children;
|
||
};
|
||
|
||
export const LayoutConfig: RuntimeConfig['layout'] = () => {
|
||
const [getSelectProject, setSelectProject] = useState<LevelKeysProps[]>([]);
|
||
const { snap } = useMyState();
|
||
const navigate = useNavigate();
|
||
const permissionsList = (snap.session.permissions || [])
|
||
.filter((p: any) => p.type !== 'Button' && p.path)
|
||
.sort((a: any, b: any) => a._lft - b._lft)
|
||
.map((p: any) => ({ value: p.path, label: p.name }));
|
||
const quickLinks = [
|
||
{ label: '工单Bi', path: '/work_order/work_bi' },
|
||
{ label: '合同Bi', path: '/contract/contracts_bi' },
|
||
{ label: '收费Bi', path: '/charge/charge_bi' },
|
||
{ label: '项目Bi', path: '/asset/asset_bi' },
|
||
];
|
||
const handleLoadProject = async () => {
|
||
let res = await Apis.Common.Auth.GetProjects();
|
||
setSelectProject(
|
||
res?.data?.map((item) => ({
|
||
value: item.id,
|
||
label: item.name,
|
||
})),
|
||
);
|
||
};
|
||
|
||
const [stateOpenKeys, setStateOpenKeys] = useState(['2', '23']);
|
||
const getLevelKeys: any = (items1: LevelKeysProps[]) => {
|
||
const key: Record<string, number> = {};
|
||
const func = (items2: LevelKeysProps[], level = 1) => {
|
||
items2?.forEach((item) => {
|
||
if (item.key) {
|
||
key[item.key] = level;
|
||
}
|
||
if (item.children) {
|
||
func(item.children, level + 1);
|
||
}
|
||
});
|
||
};
|
||
func(items1);
|
||
return key;
|
||
};
|
||
|
||
useEffect(() => {
|
||
handleLoadProject('');
|
||
}, []);
|
||
|
||
return {
|
||
title: '',
|
||
// 首页 logo
|
||
logo: (
|
||
<div style={{ width: 136, display: 'flex', justifyContent: 'center' }}>
|
||
<img
|
||
src={
|
||
snap.session?.company_configs?.config_value?.admin_logo
|
||
? snap.session?.company_configs?.config_value?.admin_logo[0]?.url
|
||
: ''
|
||
}
|
||
style={{ width: 'auto', height: '42px' }}
|
||
/>
|
||
</div>
|
||
),
|
||
layout: 'mix',
|
||
siderWidth: 180,
|
||
colorPrimary: '#1890ff',
|
||
pure: history.location.pathname === '/login',
|
||
avatarProps: {
|
||
render: () => <AvatarProps user={snap.session.user} />,
|
||
},
|
||
headerContentRender: () => (
|
||
<div className="headerContentRender">
|
||
<div style={{ display: 'flex', alignItems: 'center', gap: 20 }}>
|
||
<HeaderSearch permissionsList={permissionsList} />
|
||
</div>
|
||
<Space size={10}>
|
||
{/* <Button
|
||
type="default"
|
||
shape="circle"
|
||
icon={<SettingOutlined />}
|
||
onClick={() => history.push('/system/sys_permissions')}
|
||
/> */}
|
||
<Select
|
||
onSearch={handleLoadProject}
|
||
options={getSelectProject}
|
||
allowClear
|
||
style={{ width: 160 }}
|
||
defaultValue={snap.session.current_project?.id}
|
||
onChange={(e: any) => {
|
||
Apis.Common.Auth.SwitchProject({
|
||
project_id: e ? e?.toString() : 'all',
|
||
}).then(() => {
|
||
window.location.reload();
|
||
});
|
||
console.log(e, 'e');
|
||
}}
|
||
placeholder="选择项目"
|
||
/>
|
||
</Space>
|
||
</div>
|
||
),
|
||
//水印设置
|
||
waterMarkProps: {
|
||
content: snap.session.user?.username,
|
||
},
|
||
defaultCollapsed: true,
|
||
collapsedButtonRender: false,
|
||
token: {
|
||
bgLayout: '#f6f6f6',
|
||
// header: {
|
||
// colorBgHeader: '#1B1F3B',
|
||
// colorHeaderTitle: '#f8f8f8',
|
||
// colorTextRightActionsItem: '#FFF',
|
||
// heightLayoutHeader: 50,
|
||
// },
|
||
//菜单背景色
|
||
sider: {
|
||
colorMenuBackground: '#fff',
|
||
colorTextMenuSelected: '#1890ff', // 菜单激活项字体颜色设置为蓝色
|
||
},
|
||
},
|
||
// 上下菜单
|
||
menuItemRender: (item, dom) => <Link to={item.path || '/'}>{dom}</Link>,
|
||
//点击目录,收起其他菜单
|
||
menuCollapse: true,
|
||
// //左右菜单
|
||
menuRender: () => {
|
||
let objjs: any = [];
|
||
snap.session.permissions?.forEach((res: any) => {
|
||
objjs.push(res);
|
||
});
|
||
let data = objjs.sort((a: any, b: any) => {
|
||
return a._lft - b._lft;
|
||
});
|
||
const menus = loopMenu(data);
|
||
|
||
const levelKeys: any = getLevelKeys(menus as LevelKeysProps[]);
|
||
const onOpenChange: MenuProps['onOpenChange'] = (openKeys) => {
|
||
const currentOpenKey = openKeys.find(
|
||
(key) => !stateOpenKeys.includes(key),
|
||
);
|
||
// open
|
||
if (currentOpenKey !== undefined) {
|
||
const repeatIndex = openKeys
|
||
.filter((key) => key !== currentOpenKey)
|
||
.findIndex((key) => levelKeys[key] === levelKeys[currentOpenKey]);
|
||
setStateOpenKeys(
|
||
openKeys
|
||
// remove repeat key
|
||
.filter((_, index) => index !== repeatIndex)
|
||
// remove current level all child
|
||
.filter((key) => levelKeys[key] <= levelKeys[currentOpenKey]),
|
||
);
|
||
} else {
|
||
// close
|
||
setStateOpenKeys(openKeys);
|
||
}
|
||
};
|
||
return (
|
||
<div
|
||
style={{
|
||
position: 'relative',
|
||
width: 180,
|
||
top: 0,
|
||
left: 0,
|
||
bottom: 0,
|
||
height: '100vh',
|
||
zIndex: 100,
|
||
boxShadow: '0 2px 10px rgba(0, 0, 0, 0.1)',
|
||
}}
|
||
>
|
||
<div
|
||
style={{
|
||
position: 'fixed',
|
||
paddingTop: 60,
|
||
top: 0,
|
||
left: 0,
|
||
bottom: 0,
|
||
backgroundColor: '#fff',
|
||
overflowY: 'auto',
|
||
}}
|
||
>
|
||
<Menu
|
||
style={{ width: '165px' }}
|
||
mode="inline"
|
||
defaultSelectedKeys={[history.location.pathname]}
|
||
theme="light"
|
||
items={menus}
|
||
openKeys={stateOpenKeys}
|
||
onOpenChange={onOpenChange}
|
||
onClick={({ key }) => {
|
||
sessionStorage.setItem('breadcrumbs', '');
|
||
navigate(key);
|
||
console.log(key, 'key2');
|
||
}}
|
||
onSelect={({ key }) => {
|
||
console.log(key, 'key');
|
||
}}
|
||
/>
|
||
</div>
|
||
</div>
|
||
);
|
||
},
|
||
menuMode: 'inline',
|
||
menu: {
|
||
params: snap.session.permissions,
|
||
mode: 'inline',
|
||
request: async () => {
|
||
let objjs: any = [];
|
||
snap.session.permissions?.forEach((res: any) => {
|
||
objjs.push(res);
|
||
});
|
||
let data = objjs.sort((a: any, b: any) => {
|
||
return a._lft - b._lft;
|
||
});
|
||
const menus = loopMenu(data);
|
||
return Promise.resolve(menus);
|
||
},
|
||
},
|
||
// unAccessible: <div>unAccessible</div>,
|
||
};
|
||
};
|
||
const HeaderSearch = ({ permissionsList }: { permissionsList: any[] }) => {
|
||
const [value, setValue] = useState<string>('');
|
||
return (
|
||
<AutoComplete
|
||
value={value}
|
||
options={permissionsList}
|
||
style={{ width: 280 }}
|
||
placeholder="~输入关键字,搜索系统功能"
|
||
filterOption={(inputValue, option) =>
|
||
(option?.label as string)
|
||
?.toLowerCase()
|
||
.includes(inputValue.toLowerCase())
|
||
}
|
||
onChange={(v) => setValue(v)}
|
||
onSelect={(v) => {
|
||
setValue('');
|
||
history.push(v as string);
|
||
}}
|
||
>
|
||
搜索:
|
||
<Input allowClear size="middle" />
|
||
</AutoComplete>
|
||
);
|
||
};
|