umi#history TypeScript Examples
The following examples show how to use
umi#history.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: index.tsx From anew-server with MIT License | 6 votes |
goto = () => {
if (!history) return;
setTimeout(() => {
const { query } = history.location;
const { redirect } = query as {
redirect: string;
};
history.push(redirect || '/');
}, 10);
}
Example #2
Source File: app.tsx From ql with MIT License | 6 votes |
export function render(oldRender: any) {
request
.get(`${config.apiPrefix}user`)
.then((data) => {
if (data.data && data.data.username) {
return oldRender();
}
localStorage.removeItem(config.authKey);
history.push('/login');
oldRender();
})
.catch((e) => {
console.log(e);
if (e.response && e.response.status === 401) {
localStorage.removeItem(config.authKey);
history.push('/login');
oldRender();
}
});
}
Example #3
Source File: StaffAdminAvatarDropdown.tsx From dashboard with Apache License 2.0 | 6 votes |
onMenuClick = (event: { key: React.Key; keyPath: React.Key[]; item: React.ReactInstance }) => {
const { key } = event;
if (key === 'settings'){
history.push('/staff-admin/company-management/role')
return;
}
if (key === 'logout') {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'staffAdmin/logout',
});
}
return;
}
history.push(`/staff-admin/${key}`);
};
Example #4
Source File: index.tsx From sidebar with Apache License 2.0 | 6 votes |
BottomNavBar: React.FC<BottomNavBarProps> = (props) => {
const {links} = props;
return (
<div className={styles.bottomNavbar}>
<Row className={styles.navList}>
{links.map((link, index) => {
const isActive = window.location.href.includes(link.url);
const id = link.url + link.title;
const span = Math.floor((24 / links.length));
return (
<Col key={id} className={styles.navItem} span={span}>
<Button
type={'link'}
onClick={() => {
if (!isActive) {
history.push(link.url)
}
}}
icon={getIcon(link.icon)}
block={true}
disabled={link.disabled || false}
className={(link.disabled ? 'disabled' : '') + (isActive ? ' active' : '')}
>{link.title}</Button>
{index < links.length - 1 && (
<Divider type={'vertical'}/>
)}
</Col>
);
})}
</Row>
</div>
);
}
Example #5
Source File: app.tsx From ant-design-pro-V5-multitab with MIT License | 6 votes |
export async function getInitialState(): Promise<{
settings?: LayoutSettings;
currentUser?: API.CurrentUser;
collapsed?: boolean | undefined
fetchUserInfo?: () => Promise<API.CurrentUser | undefined>;
}> {
const fetchUserInfo = async () => {
try {
const currentUser = await queryCurrent();
return currentUser;
} catch (error) {
history.push('/user/login');
}
return undefined;
};
// 如果是登录页面,不执行
if (history.location.pathname !== '/user/login') {
const currentUser = await fetchUserInfo();
return {
fetchUserInfo,
currentUser,
settings: defaultSettings,
collapsed: false
};
}
return {
fetchUserInfo,
settings: defaultSettings,
collapsed: false
};
}
Example #6
Source File: index.tsx From scorpio-h5-design with MIT License | 6 votes |
export default function(props: {
children: React.ReactChild;
}) {
const onMenuClick = function(key: string) {
history.push(key);
};
return (
<div className="layout-manage">
<div className="layout-manage-left">
<Menu
defaultSelectedKeys={['1']}
defaultOpenKeys={['sub1']}
mode="inline"
onSelect={(info) => { onMenuClick(info.key as string); }}
>
<Menu.Item key="/manage/page" icon={<PieChartOutlined />}>
页面搭建
</Menu.Item>
{/* <Menu.Item key="/manage/pageTemplate" icon={<PieChartOutlined />}>
页面模板
</Menu.Item> */}
<Menu.Item key="/manage/category" icon={<PieChartOutlined />}>
组件分类
</Menu.Item>
<Menu.Item key="/manage/component" icon={<PieChartOutlined />}>
组件开发(dev)
</Menu.Item>
</Menu>
</div>
<div className="layout-manage-right">
{props.children}
</div>
</div>
);
}
Example #7
Source File: 404.tsx From ui-visualization with MIT License | 6 votes |
NoFoundPage: React.FC<{}> = () => (
<Result
status="404"
title="404"
subTitle="Sorry, the page you visited does not exist."
extra={
<Button type="primary" onClick={() => history.push('/')}>
Back Home
</Button>
}
/>
)
Example #8
Source File: AvatarDropdown.tsx From anew-server with MIT License | 6 votes |
loginOut = async () => {
await AuthLogout();
localStorage.removeItem('token');
localStorage.removeItem('expires');
const { query = {}, pathname } = history.location;
const { redirect } = query;
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: pathname,
}),
});
}
}
Example #9
Source File: app.tsx From admin-fe with MIT License | 6 votes |
export async function render(oldRender: Function) {
function redirectToLogin() {
history.push('/login')
oldRender()
}
try {
const data = await getAdminInfo()
if (data == null) redirectToLogin()
oldRender()
} catch (ex) {
console.error(ex)
redirectToLogin()
}
}
Example #10
Source File: AvatarDropdown.tsx From ant-design-pro-V4 with MIT License | 6 votes |
onMenuClick = (event: { key: React.Key; keyPath: React.Key[]; item: React.ReactInstance }) => {
const { key } = event;
if (key === 'todo') {
history.push('/todo');
return
}
if (key === 'logout') {
const { dispatch } = this.props;
if (dispatch) {
dispatch({
type: 'login/logout',
});
}
return;
}
history.push(`/account/${key}`);
};
Example #11
Source File: app.tsx From anew-server with MIT License | 6 votes |
errResponseInterceptor = async (response: Response, options: RequestOptionsInit) => {
const data: API.Result = await response.clone().json();
if (!response) {
message.error('您的网络发生异常,无法连接服务器');
return response;
}
if (!data.status) {
message.error(data.message);
if (data.code === 401) {
localStorage.removeItem('token');
localStorage.removeItem('expires');
history.push('/user/login')
}
} else {
if (data.code !== 200) {
message.error(data.message);
}
}
return response;
}
Example #12
Source File: 404.tsx From ant-design-pro-V4 with MIT License | 6 votes |
NoFoundPage: React.FC = () => (
<Result
status="404"
title="404"
subTitle="Sorry, the page you visited does not exist."
extra={
<Button type="primary" onClick={() => history.push('/')}>
Back Home
</Button>
}
/>
)
Example #13
Source File: AvatarDropdown.tsx From ant-design-pro-V5-multitab with MIT License | 5 votes |
AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => {
const { initialState, setInitialState } = useModel('@@initialState');
const onMenuClick = useCallback(
(event: {
key: React.Key;
keyPath: React.Key[];
item: React.ReactInstance;
domEvent: React.MouseEvent<HTMLElement>;
}) => {
const { key } = event;
if (key === 'logout' && initialState) {
setInitialState({ ...initialState, currentUser: undefined });
loginOut();
return;
}
history.push(`/account/${key}`);
},
[initialState, setInitialState],
);
const loading = (
<span className={`${styles.action} ${styles.account}`}>
<Spin
size="small"
style={{
marginLeft: 8,
marginRight: 8,
}}
/>
</span>
);
if (!initialState) {
return loading;
}
const { currentUser } = initialState;
if (!currentUser || !currentUser.name) {
return loading;
}
const menuHeaderDropdown = (
<Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
{menu && (
<Menu.Item key="center">
<UserOutlined />
个人中心
</Menu.Item>
)}
{menu && (
<Menu.Item key="settings">
<SettingOutlined />
个人设置
</Menu.Item>
)}
{menu && <Menu.Divider />}
<Menu.Item key="logout">
<LogoutOutlined />
退出登录
</Menu.Item>
</Menu>
);
return (
<HeaderDropdown overlay={menuHeaderDropdown}>
<span className={`${styles.action} ${styles.account}`}>
<Avatar size="small" className={styles.avatar} src={currentUser.avatar} alt="avatar" />
<span className={`${styles.name} anticon`}>{currentUser.name}</span>
</span>
</HeaderDropdown>
);
}
Example #14
Source File: app.tsx From anew-server with MIT License | 5 votes |
layout: RunTimeLayoutConfig = ({ initialState }) => {
return {
rightContentRender: () => <RightContent />,
disableContentMargin: false,
waterMarkProps: {
content: initialState?.currentUser?.name,
},
footerRender: () => <Footer />,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== loginPath) {
history.push(loginPath);
}
},
menu: {
// 每当 initialState?.currentUser?.userid 发生修改时重新执行 request
params: {
userId: initialState?.currentUser?.id,
},
request: async (params, defaultMenuData) => {
if (!params.userId) return []
const menuData = await (await GetMenuTree()).data;
return menuData;
},
},
// links: isDev
// ? [
// <Link to="/umi/plugin/openapi" target="_blank">
// <LinkOutlined />
// <span>OpenAPI 文档</span>
// </Link>,
// <Link to="/~docs">
// <BookOutlined />
// <span>业务组件文档</span>
// </Link>,
// ]
// : [],
menuHeaderRender: undefined,
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
...initialState?.settings,
};
}
Example #15
Source File: app.tsx From ant-design-pro-V5-multitab with MIT License | 5 votes |
layout: RunTimeLayoutConfig = ({ initialState, setInitialState }) => {
return {
rightContentRender: () => <RightContent />,
disableContentMargin: true,
footerRender: () => <Footer />,
headerRender: () => <HeaderRender />,
headerHeight: 93,
onPageChange: () => {
const { location } = history;
// 如果没有登录,重定向到 login
if (!initialState?.currentUser && location.pathname !== '/user/login') {
history.push('/user/login');
}
},
onCollapse: (collapsed) => {
setInitialState({ ...initialState, collapsed })
},
// menuHeaderRender: (logo, title, props) => {
// console.log(logo);
// console.log(title);
// console.log(props);
// },
// patchMenus: (menuData: Array<any>) => {
// let menuArr: Array<any> = [];
// menuData.forEach((item) => {
// if (item.path === "/") {
// menuArr = [...menuArr, ...item.children]
// } else {
// menuArr.push(item)
// }
// })
// return menuArr
// },
// childrenRender: (children) => {
// return (
// <AliveScope>
// {children}
// </AliveScope>
// )
// },
// 自定义 403 页面
// unAccessible: <div>unAccessible</div>,
...initialState?.settings,
};
}
Example #16
Source File: app.tsx From anew-server with MIT License | 5 votes |
/**
* @see https://umijs.org/zh-CN/plugins/plugin-initial-state
* */
export async function getInitialState(): Promise<{
settings?: Partial<LayoutSettings>;
currentUser?: API.UserInfo;
DictObj?: any;
fetchUserInfo?: () => Promise<API.UserInfo | undefined>;
fetchDictInfo?: () => Promise<any | undefined>;
}> {
const fetchUserInfo = async () => {
try {
const currentUser: API.UserInfo = await (await getUserInfo()).data;
return currentUser;
} catch (error) {
history.push(loginPath);
}
return undefined;
};
// 初始化字典信息
const fetchDictInfo = async () => {
try {
const DictObj: any = (await queryDictsByAllType({ all_type: true })).data
return DictObj;
} catch (error) {
history.push(loginPath);
}
return undefined;
};
// 如果是登录页面,不执行
if (history.location.pathname !== loginPath) {
const currentUser = await fetchUserInfo();
const DictObj = await fetchDictInfo();
return {
fetchUserInfo,
currentUser,
DictObj,
settings: {},
};
}
return {
fetchUserInfo,
fetchDictInfo,
settings: {},
};
}
Example #17
Source File: edit.tsx From dashboard with Apache License 2.0 | 5 votes |
CreateRole: React.FC = () => {
const [currentRole, setCurrentRole] = useState<RoleItem>({
is_default: False,
});
const [itemID, setItemID] = useState<string>('');
const roleFormRef = useRef<FormInstance>();
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const id = params.get('id');
if (id) {
setItemID(id);
} else {
message.error('传入参数请带上ID');
}
}, []);
useEffect(() => {
if (itemID) {
const hide = message.loading('加载数据中');
Get(itemID).then((res) => {
hide();
if (res.code === 0) {
setCurrentRole(res.data);
roleFormRef.current?.setFieldsValue(res.data);
} else {
message.error(res.message);
}
});
}
}, [itemID]);
return (
<PageContainer
onBack={() => history.goBack()}
backIcon={<LeftOutlined />}
header={{
title: '修改角色',
}}
>
<ProCard>
<RoleForm
// @ts-ignore
formRef={roleFormRef}
mode={'edit'}
onFinish={async (values) => {
const hide = message.loading('处理中');
const res: CommonResp = await Update(values);
hide();
if (res.code === 0) {
history.push('/staff-admin/company-management/role');
message.success('修改成功');
return true;
}
if (res.message) {
message.error(res.message);
return false;
}
message.error('修改失败');
return false;
}}
currentItem={currentRole}
/>
</ProCard>
</PageContainer>
);
}
Example #18
Source File: index.tsx From ql with MIT License | 5 votes |
Login = () => {
const handleOk = (values: any) => {
request
.post(`${config.apiPrefix}login`, {
data: {
username: values.username,
password: values.password,
},
})
.then((data) => {
if (data.code === 200) {
localStorage.setItem(config.authKey, data.token);
history.push('/crontab');
} else if (data.code === 100) {
message.warn(data.msg);
} else {
message.error(data.msg);
}
})
.catch(function (error) {
console.log(error);
});
};
useEffect(() => {
const isAuth = localStorage.getItem(config.authKey);
if (isAuth) {
history.push('/crontab');
}
}, []);
return (
<div className={styles.container}>
<div className={styles.content}>
<div className={styles.top}>
<div className={styles.header}>
<img
alt="logo"
className={styles.logo}
src="https://qinglong.whyour.cn/qinglong.png"
/>
<span className={styles.title}>{config.siteName}</span>
</div>
</div>
<div className={styles.main}>
<Form onFinish={handleOk}>
<FormItem
name="username"
rules={[{ required: true, message: '请输入用户名' }]}
hasFeedback
>
<Input placeholder="用户名" autoFocus />
</FormItem>
<FormItem
name="password"
rules={[{ required: true, message: '请输入密码' }]}
hasFeedback
>
<Input type="password" placeholder="密码" />
</FormItem>
<Row>
<Button
type="primary"
htmlType="submit"
style={{ width: '100%' }}
>
登录
</Button>
</Row>
</Form>
</div>
</div>
</div>
);
}
Example #19
Source File: create.tsx From dashboard with Apache License 2.0 | 5 votes |
CreateContactWay: React.FC = () => {
const [allStaffs, setAllStaffs] = useState<StaffOption[]>([]);
const [allTagGroups, setAllTagGroups] = useState<CustomerTagGroupItem[]>([]);
useEffect(() => {
QueryCustomerTagGroups({page_size: 5000}).then((res) => {
if (res.code === 0) {
setAllTagGroups(res?.data?.items);
} else {
message.error(res.message);
}
});
}, []);
useEffect(() => {
QuerySimpleStaffs({ page_size: 5000 }).then((res) => {
if (res.code === 0) {
setAllStaffs(
res?.data?.items?.map((item: SimpleStaffInterface) => {
return {
label: item.name,
value: item.ext_id,
...item,
};
}) || [],
);
} else {
message.error(res.message);
}
});
}, []);
return (
<PageContainer
onBack={() => history.goBack()}
backIcon={<LeftOutlined />}
header={{
title: '创建渠道活码',
}}
>
<ProCard>
<ContactWayForm
mode={'create'}
onFinish={async (values) => {
const params = { ...values };
const hide = message.loading('处理中');
const res: CommonResp = await Create(params);
hide();
if (res.code === 0) {
history.push('/staff-admin/customer-growth/contact-way');
message.success('添加成功');
return true;
}
if (res.message) {
message.error(res.message);
return false;
}
message.error('添加失败');
return false;
}}
staffs={allStaffs}
tagGroups={allTagGroups}
/>
</ProCard>
</PageContainer>
);
}
Example #20
Source File: bridge.ts From scorpio-h5-design with MIT License | 5 votes |
export function isMobile(){
const {pathname} = history.location;
return pathname === '/mobile';
}
Example #21
Source File: login.ts From ant-design-pro-V4 with MIT License | 5 votes |
Model: LoginModelType = {
namespace: 'login',
state: {
status: undefined,
},
effects: {
*login({ payload }, { call, put }) {
const response = yield call(fakeAccountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
// Login successfully
if (response.status === 'ok') {
const urlParams = new URL(window.location.href);
const params = getPageQuery();
message.success('? ? ? 登录成功!');
let { redirect } = params as { redirect: string };
if (redirect) {
const redirectUrlParams = new URL(redirect);
if (redirectUrlParams.origin === urlParams.origin) {
redirect = redirect.substr(urlParams.origin.length);
if (window.routerBase !== '/') {
redirect = redirect.replace(window.routerBase, '/');
}
if (redirect.match(/^\/.*#/)) {
redirect = redirect.substr(redirect.indexOf('#') + 1);
}
} else {
window.location.href = '/';
return;
}
}
history.replace(redirect || '/');
}
},
logout() {
const { redirect } = getPageQuery();
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: window.location.href,
}),
});
}
},
},
reducers: {
changeLoginStatus(state, { payload }) {
setAuthority(payload.currentAuthority);
return {
...state,
status: payload.status,
type: payload.type,
};
},
},
}
Example #22
Source File: login.ts From ui-visualization with MIT License | 5 votes |
Model: LoginModelType = {
namespace: 'login',
state: {
status: undefined,
},
effects: {
*login({ payload }, { call, put }) {
const response = yield call(fakeAccountLogin, payload);
yield put({
type: 'changeLoginStatus',
payload: response,
});
// Login successfully
if (response.status === 'ok') {
const urlParams = new URL(window.location.href);
const params = getPageQuery();
let { redirect } = params as { redirect: string };
if (redirect) {
const redirectUrlParams = new URL(redirect);
if (redirectUrlParams.origin === urlParams.origin) {
redirect = redirect.substr(urlParams.origin.length);
if (redirect.match(/^\/.*#/)) {
redirect = redirect.substr(redirect.indexOf('#') + 1);
}
} else {
window.location.href = '/';
return;
}
}
history.replace(redirect || '/');
}
},
logout() {
const { redirect } = getPageQuery();
// Note: There may be security issues, please note
if (window.location.pathname !== '/user/login' && !redirect) {
history.replace({
pathname: '/user/login',
search: stringify({
redirect: window.location.href,
}),
});
}
},
},
reducers: {
changeLoginStatus(state, { payload }) {
setAuthority(payload.currentAuthority);
return {
...state,
status: payload.status,
type: payload.type,
};
},
},
}
Example #23
Source File: app.ts From scorpio-h5-design with MIT License | 5 votes |
history.listen((location: any, action: any) => {
if (location.pathname !== '/design') {
doChildrenDestroy();
}
});
Example #24
Source File: create.tsx From dashboard with Apache License 2.0 | 5 votes |
CreateCustomerMassMsg: React.FC = () => {
const [currentCustomerMassMsg] = useState<CustomerMassMsgItem>();
const formRef = useRef<FormInstance>();
return (
<PageContainer
onBack={() => history.goBack()}
backIcon={<LeftOutlined />}
header={{
title: '创建群发',
}}
>
<ProCard>
<CustomerMassMsgForm
formRef={formRef}
mode={'create'}
onFinish={async (values) => {
const params = { ...values };
const hide = message.loading('处理中');
const res: CommonResp = await Create(params);
hide();
if (res.code === 0) {
history.push('/staff-admin/customer-conversion/customer-mass-msg');
message.success('添加成功');
return true;
}
if (res.message) {
message.error(res.message);
return false;
}
message.error('添加失败');
return false;
}}
initialValues={currentCustomerMassMsg}
/>
</ProCard>
</PageContainer>
);
}
Example #25
Source File: index.tsx From scorpio-h5-design with MIT License | 4 votes |
ComponentDetail = function() {
const { setStateByObjectKeys, pageSchema, selectComponent } = useModel('bridge');
const component = selectComponent as IComponentSchema;
const { onSubmit, loading } = Model.useContainer();
const SchemaRef = useRef<{ getValue: () => any }>(null);
function onTabChange(key: string) {
if (key === 'form') {
component.generatorSchema = SchemaRef.current?.getValue();
const state = {
pageSchema: [...pageSchema],
};
setStateByObjectKeys(state);
onChildrenReady(() => {
syncState({
payload: state,
type: IMessageType.syncState,
});
});
}
}
async function handelSubmit() {
component.generatorSchema = SchemaRef.current?.getValue();
const dataURL = await window.postmate_mobile.get(childrenModel.CAPTURE);
if (dataURL) {
const file = dataURLtoFile(dataURL, new Date().getTime().toString());
const fileName = `${uuidv4()}.png`;
await ossClient.put(`design/${fileName}`, file);
component.cover = `https://scorpio-design.lxzyl.cn/design/${fileName}`;
}
onSubmit();
}
const OperationsSlot = {
right: (
<Space className="manage-component-detail-tabs-extBtn">
<Button onClick={() => history.goBack()}>返回</Button>
<Button type="primary" onClick={handelSubmit}>保存</Button>
</Space>
),
};
const debouncedloading = useDebounce(loading, { wait: 500 });
return (
<Spin
spinning={debouncedloading}
wrapperClassName="blur-loading"
indicator={<Loading />}
>
<div className="manage-component-detail">
<div className="left">
<MobileSimulator loading={loading}/>
</div>
<div className="right">
<Tabs
className="manage-component-detail-tabs"
defaultActiveKey="1"
onChange={onTabChange}
tabBarExtraContent={OperationsSlot}
>
<TabPane tab="schema可视化配置" key="schema">
<Schema ref={SchemaRef} />
</TabPane>
<TabPane tab="schema手动编辑" key="code">
<Code />
</TabPane>
<TabPane tab="组件属性配置" key="form">
<Form />
</TabPane>
<TabPane tab="容器属性配置" key="container">
<BaseLayoutConfig />
</TabPane>
</Tabs>
</div>
</div>
</Spin>
);
}
Example #26
Source File: index.tsx From ql with MIT License | 4 votes |
export default function (props: any) {
const logout = () => {
request.post(`${config.apiPrefix}logout`).then(() => {
localStorage.removeItem(config.authKey);
history.push('/login');
});
};
useEffect(() => {
const isAuth = localStorage.getItem(config.authKey);
if (!isAuth) {
history.push('/login');
}
vhCheck();
}, []);
useEffect(() => {
if (props.location.pathname === '/') {
history.push('/crontab');
}
}, [props.location.pathname]);
useEffect(() => {
const theme = localStorage.getItem('qinglong_dark_theme') || 'auto';
setFetchMethod(window.fetch);
if (theme === 'dark') {
enableDarkMode({
brightness: 100,
contrast: 90,
sepia: 10,
});
} else if (theme === 'light') {
disableDarkMode();
} else {
followSystemColorScheme({
brightness: 100,
contrast: 90,
sepia: 10,
});
}
}, []);
if (props.location.pathname === '/login') {
return props.children;
}
const isFirefox = navigator.userAgent.includes('Firefox');
const isSafari =
navigator.userAgent.includes('Safari') &&
!navigator.userAgent.includes('Chrome');
return (
<ProLayout
selectedKeys={[props.location.pathname]}
title={
<>
控制面板
<a href={changeLog} target="_blank" rel="noopener noreferrer">
<span
style={{
fontSize: isFirefox ? 9 : 12,
color: '#666',
marginLeft: 5,
zoom: isSafari ? 0.66 : 0.8,
}}
>
{version}
</span>
</a>
</>
}
menuItemRender={(menuItemProps: any, defaultDom: any) => {
if (
menuItemProps.isUrl ||
!menuItemProps.path ||
location.pathname === menuItemProps.path
) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
postMenuData={(menuData) => {
return [
...(menuData || []),
{
icon: <LogoutOutlined />,
name: '退出登录',
path: 'logout',
onTitleClick: () => logout(),
},
];
}}
pageTitleRender={() => '控制面板'}
{...defaultProps}
>
{props.children}
</ProLayout>
);
}
Example #27
Source File: BasicLayout.tsx From ant-design-pro-V4 with MIT License | 4 votes |
BasicLayout: React.FC<BasicLayoutProps> = (props) => {
const {
dispatch,
children,
settings,
location = {
pathname: '/',
},
} = props;
const menuDataRef = useRef<MenuDataItem[]>([]);
useEffect(() => {
if (dispatch) {
dispatch({
type: 'user/fetchCurrent',
});
}
}, []);
/** Init variables */
const handleMenuCollapse = (payload: boolean): void => {
if (dispatch) {
dispatch({
type: 'global/changeLayoutCollapsed',
payload,
});
}
};
// get children authority
const authorized = useMemo(
() =>
getMatchMenu(location.pathname || '/', menuDataRef.current).pop() || {
authority: undefined,
},
[location.pathname],
);
const { formatMessage } = useIntl();
return (
<ProLayout
logo={logo}
formatMessage={formatMessage}
{...props}
{...settings}
onCollapse={handleMenuCollapse}
onMenuHeaderClick={() => history.push('/')}
menuItemRender={(menuItemProps, defaultDom) => {
if (
menuItemProps.isUrl ||
!menuItemProps.path ||
location.pathname === menuItemProps.path
) {
return defaultDom;
}
return <Link to={menuItemProps.path}>{defaultDom}</Link>;
}}
breadcrumbRender={(routers = []) => [
{
path: '/',
breadcrumbName: formatMessage({ id: 'menu.home' }),
},
...routers,
]}
itemRender={(route, params, routes, paths) => {
const first = routes.indexOf(route) === 0;
return first ? (
<Link to={paths.join('/')}>{route.breadcrumbName}</Link>
) : (
<span>{route.breadcrumbName}</span>
);
}}
footerRender={() => {
if (settings.footerRender || settings.footerRender === undefined) {
return defaultFooterDom;
}
return null;
}}
menuDataRender={menuDataRender}
rightContentRender={() => <RightContent />}
postMenuData={(menuData) => {
menuDataRef.current = menuData || [];
return menuData || [];
}}
waterMarkProps={{
content: 'Ant Design Pro',
fontColor: 'rgba(24,144,255,0.15)',
}}
>
<Authorized authority={authorized!.authority} noMatch={noMatch}>
{children}
</Authorized>
</ProLayout>
);
}
Example #28
Source File: index.tsx From ant-design-pro-V5-multitab with MIT License | 4 votes |
Tabs = () => {
const { initialState } = useModel<any>("@@initialState");
const { collapsed } = initialState;
const { tabList, dispatch, active, showTabs, tabsWidth, tabWidth, tarnslateX } = useModel("system");
const { dropScope, clear } = useAliveController();
const onSortEnd = ({ oldIndex, newIndex }: { oldIndex: number, newIndex: number }) => {
const dataSource = JSON.parse(JSON.stringify(tabList))
const activeItem = dataSource[active as number]
dataSource.splice(newIndex, 0, dataSource.splice(oldIndex, 1)[0]);
const movedActiveIndex = dataSource.findIndex((item: string) => item === activeItem)
dispatch({ type: "CHANGESTATE", payload: { tabList: dataSource, active: movedActiveIndex } })
}
// 当前的索引值active showTabs一排能展示多少个
// 计算应该在菜单展示的菜单有哪些
const arr: any[] = []
if (tabList.length > showTabs) {
// 前面隐藏的元素
const beforeTab = Math.floor(tarnslateX / tabWidth);
// 后面隐藏的元素
const afterTab = Math.floor(tarnslateX / tabWidth) + showTabs
tabList.forEach((item, index) => {
if (index < beforeTab) {
arr.push(item)
}
if (index >= afterTab) {
arr.push(item)
}
})
}
const menuMore = (
<Menu onClick={(e) => {
// 判断点击多余tab的展示移动距离是多少
// 计算超出了多少
// tabsWidth tabWidth showTabs 100是右边操作的距离目前写死
const isBeyondDistance = ((showTabs as number) * (tabWidth as number)) - (tabsWidth as number) + 100;
// TODO 找到当前点击的索引值
const curClickIndex = tabList?.findIndex(item => item.pathname === e.key) as number;
// 能展示多少个
const totalShowIndex = (showTabs as number) - 1;
if (curClickIndex > totalShowIndex) {
// 计算移动的距离
const x = (curClickIndex - totalShowIndex) * (tabWidth as number) + isBeyondDistance
dispatch({ type: 'CHANGESTATE', payload: { tarnslateX: x, active: curClickIndex } })
} else {
dispatch({ type: 'CHANGESTATE', payload: { tarnslateX: tabWidth * curClickIndex, active: curClickIndex } })
}
history.push({ ...tabList[curClickIndex] })
}}>
{
arr.map(item => {
return <Menu.Item key={item.pathname}> {item.title}</Menu.Item>
})
}
</Menu>
);
const menu = (
<Menu onClick={(e) => {
let activeIndex: number = 0;
const localTablist = JSON.parse(JSON.stringify(tabList))
switch (e.key) {
case "closeCurrent": {
const currentName = localTablist[active].keepAliveName
if (active > 0) {
activeIndex = active - 1
const timer = setTimeout(() => {
clearTimeout(timer)
history.push(tabList[activeIndex])
}, 10)
} else {
activeIndex = 0
const timer = setTimeout(() => {
clearTimeout(timer)
history.push(localTablist[activeIndex])
}, 10)
}
const unlisten = history.listen(() => {
unlisten()
const dropTimer = setTimeout(() => {
clearTimeout(dropTimer)
dropScope(currentName)
}, 10)
})
localTablist.splice(active, 1)
dispatch({ type: "CHANGESTATE", payload: { tabList: localTablist, active: activeIndex, tarnslateX: 0 } })
break;
}
case "closeOther": {
const needDelete = localTablist.filter((item: any, index: number) => index !== active);
const needUpdate = localTablist.filter((item: any, index: number) => index === active);
needDelete.forEach((item: any) => dropScope(item.keepAliveName));
dispatch({ type: "CHANGESTATE", payload: { tabList: needUpdate, active: 0, tarnslateX: 0 } })
break;
}
case "closeAll": {
const unlisten = history.listen(() => {
unlisten()
const dropTimer = setTimeout(() => {
clearTimeout(dropTimer)
clear()
}, 10)
})
const timer = setTimeout(() => {
clearTimeout(timer)
history.push("/")
}, 10)
dispatch({ type: "CHANGESTATE", payload: { tabList: [], active: 0, tarnslateX: 0 } })
break;
}
case "closeLeft": {
const needDelete = localTablist.filter((item: any, index: number) => index < active);
const needUpdate = localTablist.filter((item: any, index: number) => index >= active);
needDelete.forEach((item: any) => dropScope(item.keepAliveName));
dispatch({ type: "CHANGESTATE", payload: { tabList: needUpdate, active: 0, tarnslateX: 0 } })
break;
}
case "closeRight": {
const needDelete = localTablist.filter((item: any, index: number) => index > active);
const needUpdate = localTablist.filter((item: any, index: number) => index <= active);
needDelete.forEach((item: any) => dropScope(item.keepAliveName));
dispatch({ type: "CHANGESTATE", payload: { tabList: needUpdate, tarnslateX: 0 } })
break;
}
}
}}>
<Menu.Item key="closeCurrent">关闭当前标签</Menu.Item>
<Menu.Item key="closeOther">关闭其他标签</Menu.Item>
<Menu.Item key="closeAll">关闭全部标签</Menu.Item>
<Menu.Item key="closeLeft" disabled={active === 0}>关闭当前左边标签</Menu.Item>
<Menu.Item key="closeRight" disabled={active === tabList.length - 1}>关闭当前右边标签</Menu.Item>
</Menu>
);
useEffect(() => {
window.onresize = () => {
const width = document.getElementById("contentContainer") ? document.getElementById("contentContainer")!.getBoundingClientRect()!.width : 0;
dispatch({ type: "CHANGESTATE", payload: { tabsWidth: width, tarnslateX: 0 } })
}
const timer = setTimeout(() => {
const width = document.getElementById("contentContainer") ? document.getElementById("contentContainer")!.getBoundingClientRect()!.width : 0;
dispatch({ type: "CHANGESTATE", payload: { tabsWidth: width } })
}, 100);
return () => {
clearTimeout(timer)
}
}, [collapsed])
useEffect(() => {
const timer = setTimeout(() => {
// 需要重新计算拿到当前tab的宽度
const tabWidth = document.getElementsByClassName("link-tab")[0] ? document.getElementsByClassName("link-tab")[0]!.getBoundingClientRect().width : 120;
//计算一排能展示多少个tab 需要减去操作占用的空间100
const showTabs = Math.ceil((tabsWidth as number - 100) / tabWidth);
if (tabsWidth > 0 && tabWidth > 0) {
dispatch({ type: "CHANGESTATE", payload: { showTabs, tabWidth } })
}
}, 100);
return () => {
clearTimeout(timer)
}
}, [tabsWidth])
return (
// <div className={styles.tabs} style={{ width: initialState?.collapsed ? "calc(100vw - 41px)" : "calc(100vw - 249px)" }}>
<div className={styles.tabs} id="contentContainer">
{tabList.length > 0 && <SortableList onSortEnd={onSortEnd} axis={'x'} distance={1} />}
<div className={`${styles.tabLeftMenu} ${tabList.length >= showTabs && styles.boxShadow}`}>
{
tabList.length > showTabs && (
<>
<Dropdown overlay={menuMore} className={styles.tabMore}>
<a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
<MoreOutlined />
</a>
</Dropdown>
<Divider type='vertical' />
</>
)
}
{
tabList.length > 1 && (
<Dropdown overlay={menu} className={styles.menuRight}>
<a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
操作 <DownOutlined />
</a>
</Dropdown>
)
}
</div>
</div>
);
}
Example #29
Source File: index.tsx From scorpio-h5-design with MIT License | 4 votes |
export default function() {
const { pageId, pageSchema, selectPage, setStateByObjectKeys } = useModel('bridge');
const addPageReq = useRequest(service.addPage, {
manual: true,
});
const editPageReq = useRequest(service.editPage, {
manual: true,
});
const [visible, { toggle }] = useBoolean(false);
const [qrcodeUrl, setQrcodeUrl] = useState('');
const save = async function() {
const dataURL = await window.postmate_mobile.get(childrenModel.CAPTURE);
if (dataURL) {
const file = dataURLtoFile(dataURL, new Date().getTime().toString());
const fileName = `${uuidv4()}.png`;
await ossClient.put(`design/${fileName}`, file);
selectPage.cover = `https://scorpio-design.lxzyl.cn/design/${fileName}`;
}
let res;
if (pageId) {
res = await editPageReq.run({
_id: pageId,
pageSchema,
});
} else {
res = await addPageReq.run({
pageSchema,
});
}
return res;
};
const onSave = async function() {
if (pageSchema.length === 0) {
return message.error('请新建页面后再保存!');
}
if (selectPage.components.length === 0) {
return message.error('至少添加一个组件后再保存!');
}
const res = await save();
const state = {
pageId: res._id,
};
setStateByObjectKeys(state);
message.success('保存成功!');
};
const onVisibleChange = async function() {
if (pageSchema.length === 0) {
return message.error('请新建页面后再操作!');
}
toggle();
await save();
const dataUrl = await QRCode.toDataURL(`${config.h5Base}?id=${pageId}`, {
margin: 0,
});
console.log('dataUrl: ', dataUrl);
setQrcodeUrl(dataUrl);
};
const overviewContent = (
<div className="overview-qrcode">
<img className="overview-qrcode-img" src={qrcodeUrl} />
</div>
);
const exportJson = function() {
const blob = new Blob([JSON.stringify(pageSchema)], { type: 'application/json' });
console.log('pageSchema: ', pageSchema);
FileSaver.saveAs(blob, `${pageSchema[0].props.title}.json`);
};
return (
<div className="design-header">
<div className="design-header-operations">
<div className="item" onClick={() => { history.push('/manage/page'); }}>
<i className="iconfont icon-shouye" />
<div className="text" >首页</div>
</div>
<div className="item" onClick={onSave}>
<i className="iconfont icon-baocun" />
<div className="text" >保存</div>
<Spin spinning={addPageReq.loading || editPageReq.loading}>
</Spin>
</div>
{/* <Popover
title="真机预览"
trigger="click"
visible={visible}
onVisibleChange={onVisibleChange}
content={overviewContent}
overlayClassName="overview-qrcode-popover"
>
<div className="item">
<i className="iconfont icon-shouji" />
<div className="text">预览</div>
</div>
</Popover> */}
<div className="item" onClick={exportJson}>
<i className="iconfont icon-json" />
<div className="text">导出</div>
</div>
{/* <div className="item">
<i className="iconfont icon-html" />
<div className="text">下载</div>
<i className="iconfont icon-new" style={{position: 'absolute', color: 'red', right: 0, top: 0}}/>
</div> */}
<div className="item" onClick={() => { window.open('https://github.com/lx544690189/scorpio-h5-design'); }}>
<i className="iconfont icon-github-fill" />
<div className="text">GITHUB</div>
</div>
</div>
</div>
);
}