feat: user register & profile

This commit is contained in:
chenos 2021-08-23 21:49:44 +08:00
parent 589fca05d0
commit c82fee6162
7 changed files with 121 additions and 13 deletions

View File

@ -115,6 +115,7 @@ import * as uiSchema from './ui-schema';
const User = database.getModel('users'); const User = database.getModel('users');
const user = await User.create({ const user = await User.create({
nickname: '超级管理员',
email: process.env.ADMIN_EMAIL, email: process.env.ADMIN_EMAIL,
password: process.env.ADMIN_PASSWORD, password: process.env.ADMIN_PASSWORD,
}); });

View File

@ -8,7 +8,7 @@ export const login = {
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Input', 'x-component': 'Input',
'x-component-props': { 'x-component-props': {
placeholder: '邮箱或用户名', placeholder: '电子邮箱',
style: { style: {
// width: 240, // width: 240,
}, },

View File

@ -2,19 +2,19 @@ export const register = {
key: '46qlxqam3xk', key: '46qlxqam3xk',
type: 'object', type: 'object',
properties: { properties: {
username: { email: {
type: 'string', type: 'string',
required: true, required: true,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Input', 'x-component': 'Input',
'x-component-props': { 'x-component-props': {
placeholder: '用户名', placeholder: '电子邮箱',
style: { style: {
// width: 240, // width: 240,
}, },
}, },
}, },
pwd1: { password: {
type: 'string', type: 'string',
required: true, required: true,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
@ -26,19 +26,41 @@ export const register = {
// width: 240, // width: 240,
}, },
}, },
'x-reactions': [
{
dependencies: ['.confirm_password'],
fulfill: {
state: {
errors:
'{{$deps[0] && $self.value && $self.value !== $deps[0] ? "确认密码不匹配" : ""}}',
},
},
},
],
}, },
pwd2: { confirm_password: {
type: 'string', type: 'string',
required: true, required: true,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Password', 'x-component': 'Password',
'x-component-props': { 'x-component-props': {
placeholder: '密码', placeholder: '确认密码',
checkStrength: true, checkStrength: true,
style: { style: {
// width: 240, // width: 240,
}, },
}, },
'x-reactions': [
{
dependencies: ['.password'],
fulfill: {
state: {
errors:
'{{$deps[0] && $self.value && $self.value !== $deps[0] ? "确认密码不匹配" : ""}}',
},
},
},
],
}, },
actions: { actions: {
type: 'void', type: 'void',

View File

@ -1,10 +1,22 @@
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { createContext } from 'react'; import React, { createContext } from 'react';
import { useContext } from 'react';
import { Redirect } from 'react-router'; import { Redirect } from 'react-router';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { BaseResult } from '@ahooksjs/use-request/lib/types';
export const AuthContext = createContext(null); export interface AuthContextProps {
currentUser?: any;
service: BaseResult<any, any>;
}
export const AuthContext = createContext<AuthContextProps>({});
export const useCurrentUser = () => {
const { currentUser } = useContext(AuthContext);
return currentUser;
}
export function AuthProvider(props) { export function AuthProvider(props) {
const service = useRequest('users:check', { const service = useRequest('users:check', {

View File

@ -1,15 +1,63 @@
import React, { useContext, useEffect } from 'react'; import React, { useContext, useEffect } from 'react';
import { Button, Dropdown, Menu } from 'antd'; import { Button, Dropdown, Menu } from 'antd';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import { request } from '../../schemas'; import { request, SchemaField } from '../../schemas';
import { AuthContext, useCurrentUser } from './Auth';
import { FormButtonGroup, FormDrawer, FormLayout, Submit } from '@formily/antd';
export const UserInfo = () => { export const UserInfo = () => {
const history = useHistory(); const history = useHistory();
const { service, currentUser } = useContext(AuthContext);
return ( return (
<Dropdown <Dropdown
overlay={ overlay={
<Menu> <Menu>
<Menu.Item></Menu.Item> <Menu.Item
onClick={async () => {
const values = await FormDrawer('个人资料', () => {
return (
<FormLayout layout={'vertical'}>
<SchemaField
schema={{
type: 'object',
properties: {
email: {
type: 'string',
title: '邮箱',
'x-component': 'Input',
'x-decorator': 'FormilyFormItem',
},
nickname: {
type: 'string',
title: '昵称',
'x-component': 'Input',
'x-decorator': 'FormilyFormItem',
},
},
}}
/>
<FormDrawer.Footer>
<FormButtonGroup align="right">
<Submit onSubmit={(values) => {
}}>
</Submit>
</FormButtonGroup>
</FormDrawer.Footer>
</FormLayout>
);
}).open({
initialValues: currentUser || {},
});
const { data } = await request('users:updateProfile', {
method: 'post',
data: values,
});
service.mutate(data);
}}
>
</Menu.Item>
<Menu.Divider /> <Menu.Divider />
<Menu.Item <Menu.Item
onClick={async () => { onClick={async () => {
@ -23,7 +71,9 @@ export const UserInfo = () => {
</Menu> </Menu>
} }
> >
<Button type={'text'} className={'user-info'}></Button> <Button type={'text'} className={'user-info'}>
{currentUser?.nickname || currentUser?.email}
</Button>
</Dropdown> </Dropdown>
); );
}; };

View File

@ -1,5 +1,5 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { Spin } from 'antd'; import { message, Spin } from 'antd';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { useRequest } from 'ahooks'; import { useRequest } from 'ahooks';
import { request, SchemaRenderer } from '../../schemas'; import { request, SchemaRenderer } from '../../schemas';
@ -7,7 +7,7 @@ import { useForm } from '@formily/react';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
function Div(props) { function Div(props) {
return <div {...props}></div> return <div {...props}></div>;
} }
export function useLogin() { export function useLogin() {
@ -29,9 +29,18 @@ export function useLogin() {
export function useRegister() { export function useRegister() {
const form = useForm(); const form = useForm();
const history = useHistory();
return { return {
async run() { async run() {
await form.submit(); await form.submit();
const { data } = await request('users:register', {
method: 'post',
data: form.values,
});
message.success('注册成功,将跳转登录页');
setTimeout(() => {
history.push('/login');
}, 1000);
console.log(form.values); console.log(form.values);
}, },
}; };
@ -50,7 +59,11 @@ export function RouteSchemaRenderer({ route }) {
} }
return ( return (
<div> <div>
<SchemaRenderer components={{ Div }} scope={{ useLogin, useRegister }} schema={data} /> <SchemaRenderer
components={{ Div }}
scope={{ useLogin, useRegister }}
schema={data}
/>
</div> </div>
); );
} }

View File

@ -120,3 +120,13 @@ export async function getUserByResetToken(ctx: actions.Context, next: actions.Ne
ctx.body = user; ctx.body = user;
await next(); await next();
} }
export async function updateProfile(ctx: actions.Context, next: actions.Next) {
const { values } = ctx.action.params;
if (!ctx.state.currentUser) {
ctx.throw(401, 'Unauthorized');
}
await ctx.state.currentUser.update(values);
ctx.body = ctx.state.currentUser;
await next();
}