feat: improve the user module
This commit is contained in:
parent
ef24f7cfea
commit
5b4dd1800e
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
ACLShortcut,
|
ACLShortcut,
|
||||||
Action,
|
|
||||||
AdminLayout,
|
AdminLayout,
|
||||||
AntdConfigProvider,
|
AntdConfigProvider,
|
||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
@ -11,12 +10,13 @@ import {
|
|||||||
DesignableSwitch,
|
DesignableSwitch,
|
||||||
DocumentTitleProvider,
|
DocumentTitleProvider,
|
||||||
i18n,
|
i18n,
|
||||||
Menu,
|
|
||||||
Page,
|
|
||||||
PluginManagerProvider,
|
PluginManagerProvider,
|
||||||
|
RouteSchemaComponent,
|
||||||
RouteSwitch,
|
RouteSwitch,
|
||||||
RouteSwitchProvider,
|
RouteSwitchProvider,
|
||||||
SchemaComponentProvider,
|
SchemaComponentProvider,
|
||||||
|
SigninPage,
|
||||||
|
SignupPage,
|
||||||
SystemSettingsProvider,
|
SystemSettingsProvider,
|
||||||
SystemSettingsShortcut,
|
SystemSettingsShortcut,
|
||||||
useRequest
|
useRequest
|
||||||
@ -24,7 +24,7 @@ import {
|
|||||||
import { Spin } from 'antd';
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { I18nextProvider } from 'react-i18next';
|
import { I18nextProvider } from 'react-i18next';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { Link, MemoryRouter, NavLink } from 'react-router-dom';
|
||||||
import apiClient from './apiClient';
|
import apiClient from './apiClient';
|
||||||
|
|
||||||
const providers = [
|
const providers = [
|
||||||
@ -38,10 +38,10 @@ const providers = [
|
|||||||
PluginManagerProvider,
|
PluginManagerProvider,
|
||||||
{ components: { ACLShortcut, DesignableSwitch, CollectionManagerShortcut, SystemSettingsShortcut } },
|
{ components: { ACLShortcut, DesignableSwitch, CollectionManagerShortcut, SystemSettingsShortcut } },
|
||||||
],
|
],
|
||||||
[SchemaComponentProvider, { components: { Page, Menu, Action } }],
|
[SchemaComponentProvider, { components: { Link, NavLink } }],
|
||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
||||||
[RouteSwitchProvider, { components: { AuthLayout, AdminLayout } }],
|
[RouteSwitchProvider, { components: { AuthLayout, AdminLayout, RouteSchemaComponent, SigninPage, SignupPage } }],
|
||||||
];
|
];
|
||||||
|
|
||||||
const App = compose(...providers)(() => {
|
const App = compose(...providers)(() => {
|
||||||
|
@ -145,10 +145,13 @@ export default (apiClient: APIClient) => {
|
|||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
type: 'route',
|
type: 'route',
|
||||||
uiSchemaUid: 'dtf9j0b8p9u',
|
|
||||||
path: '/signin',
|
path: '/signin',
|
||||||
component: 'RouteSchemaComponent',
|
component: 'SigninPage',
|
||||||
title: '{{t("Sign in")}}',
|
},
|
||||||
|
{
|
||||||
|
type: 'route',
|
||||||
|
path: '/signup',
|
||||||
|
component: 'SignupPage',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
import { Menu } from 'antd';
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { DatabaseOutlined } from '@ant-design/icons';
|
|
||||||
import { SchemaComponent, useActionVisible, VisibleContext } from '../schema-component';
|
|
||||||
import { ISchema, useForm } from '@formily/react';
|
|
||||||
|
|
||||||
const useCloseAction = () => {
|
|
||||||
const { setVisible } = useActionVisible();
|
|
||||||
const form = useForm();
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
setVisible(false);
|
|
||||||
form.submit((values) => {
|
|
||||||
console.log(values);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const schema: ISchema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
drawer1: {
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
type: 'void',
|
|
||||||
title: 'Drawer Title',
|
|
||||||
properties: {
|
|
||||||
hello1: {
|
|
||||||
'x-content': 'Hello',
|
|
||||||
title: 'T1',
|
|
||||||
},
|
|
||||||
footer1: {
|
|
||||||
'x-component': 'Action.Drawer.Footer',
|
|
||||||
type: 'void',
|
|
||||||
properties: {
|
|
||||||
close1: {
|
|
||||||
title: 'Close',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ useCloseAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ProfileAction = () => {
|
|
||||||
const [visible, setVisible] = useState(false);
|
|
||||||
return (
|
|
||||||
<VisibleContext.Provider value={[visible, setVisible]}>
|
|
||||||
<Menu.Item
|
|
||||||
eventKey={'ProfileAction'}
|
|
||||||
onClick={() => {
|
|
||||||
setVisible(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
个人资料
|
|
||||||
</Menu.Item>
|
|
||||||
<SchemaComponent scope={{ useCloseAction }} schema={schema} />
|
|
||||||
</VisibleContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,9 +0,0 @@
|
|||||||
---
|
|
||||||
nav:
|
|
||||||
path: /client
|
|
||||||
group:
|
|
||||||
title: Client
|
|
||||||
path: /client
|
|
||||||
---
|
|
||||||
|
|
||||||
# CurrentUser <Badge>待定</Badge>
|
|
@ -1,4 +1,4 @@
|
|||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useState } from 'react';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
|
|
||||||
interface DocumentTitleContextProps {
|
interface DocumentTitleContextProps {
|
||||||
@ -35,3 +35,10 @@ export const DocumentTitleProvider: React.FC<{ addonBefore?: string; addonAfter?
|
|||||||
export const useDocumentTitle = () => {
|
export const useDocumentTitle = () => {
|
||||||
return useContext(DocumentTitleContext);
|
return useContext(DocumentTitleContext);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCurrentDocumentTitle = (title: string) => {
|
||||||
|
const { setTitle } = useDocumentTitle();
|
||||||
|
useEffect(() => {
|
||||||
|
setTitle(title);
|
||||||
|
}, []);
|
||||||
|
};
|
||||||
|
@ -8,7 +8,6 @@ export * from './application';
|
|||||||
export * from './async-data-provider';
|
export * from './async-data-provider';
|
||||||
export * from './board';
|
export * from './board';
|
||||||
export * from './collection-manager';
|
export * from './collection-manager';
|
||||||
export * from './current-user';
|
|
||||||
export * from './document-title';
|
export * from './document-title';
|
||||||
export * from './i18n';
|
export * from './i18n';
|
||||||
export * from './icon';
|
export * from './icon';
|
||||||
@ -17,4 +16,5 @@ export * from './record-provider';
|
|||||||
export * from './route-switch';
|
export * from './route-switch';
|
||||||
export * from './schema-component';
|
export * from './schema-component';
|
||||||
export * from './system-settings';
|
export * from './system-settings';
|
||||||
|
export * from './user';
|
||||||
|
|
||||||
|
@ -34,28 +34,39 @@ interface ToolbarItemProps {
|
|||||||
pin?: boolean;
|
pin?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const splitItems = (items: ToolbarItemProps[]) => {
|
||||||
|
const pinned = [];
|
||||||
|
const unpinned = [];
|
||||||
|
for (const item of items) {
|
||||||
|
if (item.pin) {
|
||||||
|
pinned.push(item);
|
||||||
|
} else {
|
||||||
|
unpinned.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [pinned, unpinned];
|
||||||
|
};
|
||||||
|
|
||||||
PluginManager.Toolbar = (props: ToolbarProps) => {
|
PluginManager.Toolbar = (props: ToolbarProps) => {
|
||||||
const { components } = useContext(PluginManagerContext);
|
const { components } = useContext(PluginManagerContext);
|
||||||
const { items = [] } = props;
|
const { items = [] } = props;
|
||||||
|
const [pinned, unpinned] = splitItems(items);
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'inline-block' }}>
|
<div style={{ display: 'inline-block' }}>
|
||||||
<Menu style={{ width: '100%' }} selectable={false} mode={'horizontal'} theme={'dark'}>
|
<Menu style={{ width: '100%' }} selectable={false} mode={'horizontal'} theme={'dark'}>
|
||||||
{items
|
{pinned.map((item, index) => {
|
||||||
.filter((item) => item.pin)
|
const Action = get(components, item.component);
|
||||||
.map((item, index) => {
|
return (
|
||||||
const Action = get(components, item.component);
|
Action && (
|
||||||
return (
|
<ToolbarItemContext.Provider key={index} value={item}>
|
||||||
Action && (
|
<Action />
|
||||||
<ToolbarItemContext.Provider key={index} value={item}>
|
</ToolbarItemContext.Provider>
|
||||||
<Action />
|
)
|
||||||
</ToolbarItemContext.Provider>
|
);
|
||||||
)
|
})}
|
||||||
);
|
{unpinned.length > 0 && (
|
||||||
})}
|
<Menu.SubMenu popupClassName={'pm-sub-menu'} key={'more'} title={<MoreOutlined />}>
|
||||||
<Menu.SubMenu key={'more'} title={<MoreOutlined />}>
|
{unpinned.map((item, index) => {
|
||||||
{items
|
|
||||||
.filter((item) => !item.pin)
|
|
||||||
.map((item, index) => {
|
|
||||||
const Action = get(components, item.component);
|
const Action = get(components, item.component);
|
||||||
return (
|
return (
|
||||||
Action && (
|
Action && (
|
||||||
@ -65,11 +76,12 @@ PluginManager.Toolbar = (props: ToolbarProps) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
<Menu.Divider key={'divider'}></Menu.Divider>
|
{unpinned.length > 0 && <Menu.Divider key={'divider'}></Menu.Divider>}
|
||||||
<Menu.Item key={'plugins'} disabled icon={<SettingOutlined />}>
|
<Menu.Item key={'plugins'} disabled icon={<SettingOutlined />}>
|
||||||
管理插件
|
管理插件
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -7,9 +7,9 @@ import {
|
|||||||
PluginManager,
|
PluginManager,
|
||||||
RemoteSchemaComponent,
|
RemoteSchemaComponent,
|
||||||
useDocumentTitle,
|
useDocumentTitle,
|
||||||
|
useRoute,
|
||||||
useSystemSettings
|
useSystemSettings
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
import { useRoute } from '../../hooks';
|
|
||||||
|
|
||||||
export function AdminLayout(props: any) {
|
export function AdminLayout(props: any) {
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
@ -64,7 +64,7 @@ export function AdminLayout(props: any) {
|
|||||||
{ component: 'SystemSettingsShortcut' },
|
{ component: 'SystemSettingsShortcut' },
|
||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
<CurrentUser.Dropdown />
|
<CurrentUser />
|
||||||
</div>
|
</div>
|
||||||
</Layout.Header>
|
</Layout.Header>
|
||||||
<Layout>
|
<Layout>
|
||||||
|
@ -2,7 +2,13 @@ import React from 'react';
|
|||||||
|
|
||||||
export function AuthLayout(props: any) {
|
export function AuthLayout(props: any) {
|
||||||
return (
|
return (
|
||||||
<div style={{ maxWidth: 320, margin: '0 auto', paddingTop: '20vh' }}>
|
<div
|
||||||
|
style={{
|
||||||
|
maxWidth: 320,
|
||||||
|
margin: '0 auto',
|
||||||
|
// paddingTop: '20vh'
|
||||||
|
}}
|
||||||
|
>
|
||||||
<h1>NocoBase</h1>
|
<h1>NocoBase</h1>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,2 +1,4 @@
|
|||||||
export * from './admin-layout';
|
export * from './admin-layout';
|
||||||
export * from './auth-layout';
|
export * from './auth-layout';
|
||||||
|
export * from './route-schema-component';
|
||||||
|
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { RemoteSchemaComponent, useRoute } from '../../../';
|
||||||
|
|
||||||
|
export function RouteSchemaComponent(props: any) {
|
||||||
|
const route = useRoute();
|
||||||
|
return <RemoteSchemaComponent uid={route.uiSchemaUid} />;
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
import React, { useState } from 'react';
|
|
||||||
import { Button, ButtonProps } from 'antd';
|
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||||
import { useA } from './hooks';
|
import { Button } from 'antd';
|
||||||
import { VisibleContext } from './context';
|
import React, { useState } from 'react';
|
||||||
import { ComposedAction } from './types';
|
|
||||||
import { ActionDrawer } from './Action.Drawer';
|
import { ActionDrawer } from './Action.Drawer';
|
||||||
|
import { VisibleContext } from './context';
|
||||||
|
import { useA } from './hooks';
|
||||||
|
import { ComposedAction } from './types';
|
||||||
|
|
||||||
export const Action: ComposedAction = observer((props) => {
|
export const Action: ComposedAction = observer((props) => {
|
||||||
const { useAction = useA, onClick, ...others } = props;
|
const { useAction = useA, onClick, ...others } = props;
|
||||||
@ -22,7 +22,7 @@ export const Action: ComposedAction = observer((props) => {
|
|||||||
run();
|
run();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{schema.title}
|
{field.title}
|
||||||
</Button>
|
</Button>
|
||||||
<RecursionField basePath={field.address} schema={schema} onlyRenderProperties />
|
<RecursionField basePath={field.address} schema={schema} onlyRenderProperties />
|
||||||
</VisibleContext.Provider>
|
</VisibleContext.Provider>
|
||||||
|
55
packages/client/src/system-settings/demos/demo1.tsx
Normal file
55
packages/client/src/system-settings/demos/demo1.tsx
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import {
|
||||||
|
AntdSchemaComponentProvider,
|
||||||
|
APIClient,
|
||||||
|
APIClientProvider,
|
||||||
|
PluginManager,
|
||||||
|
PluginManagerProvider,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
SystemSettingsProvider,
|
||||||
|
SystemSettingsShortcut,
|
||||||
|
useSystemSettings
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
const apiClient = new APIClient();
|
||||||
|
|
||||||
|
const mock = new MockAdapter(apiClient.axios);
|
||||||
|
|
||||||
|
mock.onGet('/system_settings:get').reply(200, {
|
||||||
|
data: {
|
||||||
|
title: 'NocoBase',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const Demo = () => {
|
||||||
|
const { data } = useSystemSettings();
|
||||||
|
return <div>
|
||||||
|
<h3>以下为测试内容</h3>
|
||||||
|
System title: {data?.data?.title}
|
||||||
|
</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
return (
|
||||||
|
<APIClientProvider apiClient={apiClient}>
|
||||||
|
<SystemSettingsProvider>
|
||||||
|
<SchemaComponentProvider>
|
||||||
|
<AntdSchemaComponentProvider>
|
||||||
|
<PluginManagerProvider components={{ SystemSettingsShortcut }}>
|
||||||
|
<PluginManager.Toolbar
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
component: 'SystemSettingsShortcut',
|
||||||
|
pin: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Demo />
|
||||||
|
</PluginManagerProvider>
|
||||||
|
</AntdSchemaComponentProvider>
|
||||||
|
</SchemaComponentProvider>
|
||||||
|
</SystemSettingsProvider>
|
||||||
|
</APIClientProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,11 +5,18 @@ group:
|
|||||||
path: /client
|
path: /client
|
||||||
---
|
---
|
||||||
|
|
||||||
# SystemSettings <Badge>待定</Badge>
|
# SystemSettings
|
||||||
|
|
||||||
## SystemSettingsProvider
|
## SystemSettingsProvider
|
||||||
|
|
||||||
## SystemSettingsAction
|
## SystemSettingsShortcut
|
||||||
|
|
||||||
## useSystemSettings
|
## useSystemSettings
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const { data, loading, refresh } = useSystemSettings();
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
<code src="./demos/demo1.tsx"/>
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Menu } from 'antd';
|
import { Menu } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MoreOutlined, DesktopOutlined } from '@ant-design/icons';
|
import { useHistory } from 'react-router-dom';
|
||||||
import { ProfileAction } from './ProfileAction';
|
import { ProfileAction } from './ProfileAction';
|
||||||
|
|
||||||
export const CurrentUser = () => null;
|
export const CurrentUser = () => {
|
||||||
|
const history = useHistory();
|
||||||
CurrentUser.Dropdown = () => {
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: 'inline-block' }}>
|
<div style={{ display: 'inline-block' }}>
|
||||||
<Menu selectable={false} mode={'horizontal'} theme={'dark'}>
|
<Menu selectable={false} mode={'horizontal'} theme={'dark'}>
|
||||||
@ -14,7 +13,13 @@ CurrentUser.Dropdown = () => {
|
|||||||
<Menu.Item>切换角色</Menu.Item>
|
<Menu.Item>切换角色</Menu.Item>
|
||||||
<Menu.Item>语言设置</Menu.Item>
|
<Menu.Item>语言设置</Menu.Item>
|
||||||
<Menu.Divider />
|
<Menu.Divider />
|
||||||
<Menu.Item>注销</Menu.Item>
|
<Menu.Item
|
||||||
|
onClick={() => {
|
||||||
|
history.push('/signin');
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
注销
|
||||||
|
</Menu.Item>
|
||||||
</Menu.SubMenu>
|
</Menu.SubMenu>
|
||||||
</Menu>
|
</Menu>
|
||||||
</div>
|
</div>
|
105
packages/client/src/user/ProfileAction.tsx
Normal file
105
packages/client/src/user/ProfileAction.tsx
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
import { ISchema, useForm } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { Menu } from 'antd';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { SchemaComponent, useActionVisible, useRequest, VisibleContext } from '../';
|
||||||
|
|
||||||
|
const useCloseAction = () => {
|
||||||
|
const { setVisible } = useActionVisible();
|
||||||
|
const form = useForm();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
setVisible(false);
|
||||||
|
form.submit((values) => {
|
||||||
|
console.log(values);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const useCurrentUserValues = (props, options) => {
|
||||||
|
return useRequest(
|
||||||
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: {},
|
||||||
|
}),
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSaveCurrentUserValues = () => {
|
||||||
|
const { setVisible } = useActionVisible();
|
||||||
|
const form = useForm();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
form.submit((values) => {
|
||||||
|
setVisible(false);
|
||||||
|
console.log(values);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
useValues: '{{ useCurrentUserValues }}',
|
||||||
|
},
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
type: 'void',
|
||||||
|
title: '个人资料',
|
||||||
|
properties: {
|
||||||
|
nickname: {
|
||||||
|
type: 'string',
|
||||||
|
title: "{{t('Nickname')}}",
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'x-component': 'Action.Drawer.Footer',
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
cancel: {
|
||||||
|
title: 'Cancel',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useCloseAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
submit: {
|
||||||
|
title: 'Submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useSaveCurrentUserValues }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ProfileAction = () => {
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
return (
|
||||||
|
<VisibleContext.Provider value={[visible, setVisible]}>
|
||||||
|
<Menu.Item
|
||||||
|
eventKey={'ProfileAction'}
|
||||||
|
onClick={() => {
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
个人资料
|
||||||
|
</Menu.Item>
|
||||||
|
<SchemaComponent scope={{ useCurrentUserValues, useCloseAction, useSaveCurrentUserValues }} schema={schema} />
|
||||||
|
</VisibleContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
79
packages/client/src/user/SigninPage.tsx
Normal file
79
packages/client/src/user/SigninPage.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { ISchema, useForm } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { SchemaComponent, useCurrentDocumentTitle } from '..';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
name: uid(),
|
||||||
|
'x-component': 'Form',
|
||||||
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-validator': 'email',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Password',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': { placeholder: '{{t("Password")}}', style: {} },
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
properties: {
|
||||||
|
submit: {
|
||||||
|
title: '{{t("Sign in")}}',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
block: true,
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useSignin }}',
|
||||||
|
style: { width: '100%' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
properties: {
|
||||||
|
link: {
|
||||||
|
title: '{{t("Create an account")}}',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Link',
|
||||||
|
'x-content': '{{t("Create an account")}}',
|
||||||
|
'x-component-props': { to: '/signup' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSignin = () => {
|
||||||
|
const history = useHistory();
|
||||||
|
const form = useForm();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await form.submit();
|
||||||
|
console.log(form.values);
|
||||||
|
history.push('/admin');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SigninPage = () => {
|
||||||
|
useCurrentDocumentTitle('Signin');
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<SchemaComponent scope={{ useSignin }} schema={schema} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
101
packages/client/src/user/SignupPage.tsx
Normal file
101
packages/client/src/user/SignupPage.tsx
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
import { ISchema, useForm } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { useHistory } from 'react-router-dom';
|
||||||
|
import { SchemaComponent, useCurrentDocumentTitle } from '..';
|
||||||
|
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'object',
|
||||||
|
name: uid(),
|
||||||
|
'x-component': 'Form',
|
||||||
|
properties: {
|
||||||
|
email: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-validator': 'email',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': { placeholder: '{{t("Email")}}', style: {} },
|
||||||
|
},
|
||||||
|
password: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Password',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': { placeholder: '{{t("Password")}}', checkStrength: true, style: {} },
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
dependencies: ['.confirm_password'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
confirm_password: {
|
||||||
|
type: 'string',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Password',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': { placeholder: '{{t("Confirm password")}}', checkStrength: true, style: {} },
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
dependencies: ['.password'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
selfErrors: '{{$deps[0] && $self.value && $self.value !== $deps[0] ? t("Password mismatch") : ""}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
properties: {
|
||||||
|
submit: {
|
||||||
|
title: '{{t("Sign up")}}',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
block: true,
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useSignup }}',
|
||||||
|
style: { width: '100%' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
link: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
properties: {
|
||||||
|
link: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Link',
|
||||||
|
'x-component-props': { to: '/signin' },
|
||||||
|
'x-content': '{{t("Log in with an existing account")}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const useSignup = () => {
|
||||||
|
const history = useHistory();
|
||||||
|
const form = useForm();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await form.submit();
|
||||||
|
console.log(form.values);
|
||||||
|
// history.push('/signin');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SignupPage = () => {
|
||||||
|
useCurrentDocumentTitle('Signup');
|
||||||
|
return <SchemaComponent schema={schema} scope={{ useSignup }} />;
|
||||||
|
};
|
23
packages/client/src/user/index.md
Normal file
23
packages/client/src/user/index.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
---
|
||||||
|
nav:
|
||||||
|
path: /client
|
||||||
|
group:
|
||||||
|
title: Client
|
||||||
|
path: /client
|
||||||
|
---
|
||||||
|
|
||||||
|
# User
|
||||||
|
|
||||||
|
`plugin-users` 插件的前端模块
|
||||||
|
|
||||||
|
## CurrentUser
|
||||||
|
|
||||||
|
当前用户
|
||||||
|
|
||||||
|
## SigninPage
|
||||||
|
|
||||||
|
登录页
|
||||||
|
|
||||||
|
## SignupPage
|
||||||
|
|
||||||
|
注册页
|
4
packages/client/src/user/index.ts
Normal file
4
packages/client/src/user/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './CurrentUser';
|
||||||
|
export * from './SigninPage';
|
||||||
|
export * from './SignupPage';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user