Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add login function #4

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions src/Setting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export let ServerUrl: string = '';
export let IP: string = '';
export let Port: string = '';

export function setServerUrl(ip: string, port: string): void {
IP = ip;
Port = port;
ServerUrl = `${window.location.protocol}//${ip}:${port}`;
}

export function get(url: string): Promise<Response> {
const token = localStorage.getItem('token');
return fetch(url, {
method: 'GET',
headers: token ? {
'Authorization': token,
} : {},
});
}

export function postWithJSON(url: string, data: Record<string, any>): Promise<Response> {
const token = localStorage.getItem('token');
return fetch(url, {
method: 'POST',
headers: token ? {
'Authorization': token,
} : {},
body: JSON.stringify(data)
});
}

export function isLoggedIn() {
return localStorage.getItem('token') != null;
}
12 changes: 12 additions & 0 deletions src/backend/Login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import * as Setting from '../Setting';
import type { Response } from './Response';

export interface LoginForm {
userName: string;
password: string;
}

export function login(values: LoginForm): Promise<Response> {
return Setting.postWithJSON(`${Setting.ServerUrl}/login`, values)
.then(res => res.json());
}
6 changes: 6 additions & 0 deletions src/backend/Response.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface Response {
code: number;
header?: object;
error?: string;
data?: any;
}
17 changes: 13 additions & 4 deletions src/pages/Index/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import AppBar from '@mui/material/AppBar';
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Divider from '@mui/material/Divider';
import Alert from '@mui/material/Alert';
import * as Setting from '../../Setting';

// @ts-ignore
import VerticalTabs from '/src/Comp/Tab';
Expand All @@ -24,8 +26,15 @@ export default class Index extends React.Component {


render() {
if (!Setting.isLoggedIn()) {
setTimeout(() => window.location.href = '/', 1500);
return <Alert severity='error' style={{ width: '300px', margin: "auto" }} onClose={() => window.location.href = '/'}>
you are not logged in
</Alert>;
}

return (
<Box sx={{ display: 'flex'}}>
<Box sx={{ display: 'flex' }}>
<CssBaseline />

<AppBar
Expand Down Expand Up @@ -54,7 +63,7 @@ export default class Index extends React.Component {

<Toolbar>
<Typography variant='h5' noWrap component='div' sx={{ color: 'gray', flex: '80%' }}>
127.0.0.1:8080
{`${Setting.IP}:${Setting.Port}`}
</Typography>
<Typography variant='h5' noWrap component='div' sx={{ color: 'gray' }}>
Alias
Expand All @@ -75,7 +84,7 @@ export default class Index extends React.Component {
</Drawer>
<Box
component='main'
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3, mt: 10 }}
sx={{ flexGrow: 1, bgcolor: 'background.default', p: 3, mt: 10 }}
>
{/*添加主要界面*/}
<Board />
Expand All @@ -85,4 +94,4 @@ export default class Index extends React.Component {
</Box>
);
}
}
}
248 changes: 158 additions & 90 deletions src/pages/Login/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,106 +6,174 @@ import TextField from '@mui/material/TextField';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import Box from '@mui/material/Box';
import LockOutlinedIcon from '@mui/icons-material/LockOutlined';
import Typography from '@mui/material/Typography';
import Container from '@mui/material/Container';
import { createTheme, ThemeProvider } from '@mui/material/styles';
import StorageIcon from '@mui/icons-material/Storage';
import Alert, { AlertColor } from '@mui/material/Alert';
import * as LoginBackend from '../../backend/Login';
import * as Setting from '../../Setting';
import { useState } from 'react';

const theme = createTheme();

export default function Connect()
{
// @ts-ignore
const handleSubmit = function(event){
export default function Connect() {
const [ip, setIp] = useState('');
const [port, setPort] = useState('');
const [alias, setAlias] = useState('');
const [account, setAccount] = useState('');
const [password, setPassword] = useState('');
const [message, setMessage] = useState('');
const [alertSeverity, setAlertSeverity] = useState('info' as AlertColor);
const [handleAlertClose, setHandleAlertClose] = useState(() => {
});

const validate = function(value: any): boolean {
if (!value || typeof value !== 'string' || value.length === 0) {
return false;
}
return true;
};

const handleSubmit = function(event: any): void {
event.preventDefault();
const data = new FormData(event.currentTarget);
console.log({
account: data.get('account'),
password: data.get('password'),
if (!validate(ip)) {
showMessage('error', 'ip cannot be empty');
return;
} else if (!validate(port)) {
showMessage('error', 'port cannot be empty');
return;
} else if (!validate(account)) {
showMessage('error', 'account cannot be empty');
return;
} else if (!validate(password)) {
showMessage('error', 'password cannot be empty');
return;
}

Setting.setServerUrl(ip, port);

LoginBackend.login({
userName: account,
password: password,
}).then(res => {
if (res.code === 200) {
localStorage.setItem('token', res.data.token);
showMessage('success', 'login successful', () => window.location.href = '/index');
} else {
showMessage('error', `login failed: ${res.error}`);
}
});
window.location.href="/index"
};

return (
<ThemeProvider theme={theme}>
<Container component="main" maxWidth="xs">
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'blue' }}>
<StorageIcon />
</Avatar>
<Typography component="h1" variant="h5">
NutsDB
</Typography>
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
const showMessage = (severity: AlertColor, message: string, callback?: () => void) => {
if (callback) {
setHandleAlertClose(callback);
}
setAlertSeverity(severity);
setMessage(message);
};

<TextField
sx={{width:"30ch",marginRight:'2ch'}}
margin="normal"
required
id="ip"
label="IP"
name="ip"
autoFocus
/>
<TextField
sx={{width:"12ch"}}
margin="normal"
required
id="port"
label="Port"
name="port"
/>
<TextField
margin="normal"
required
fullWidth
id="alias"
label="Alias"
name="alias"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
id="account"
label="Account"
name="account"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Connect
</Button>
const renderAlert = () => {
setTimeout(() => {
if (message && message.length > 0) {
setMessage('');
}
}, 2000);
return message && message.length > 0 ? <div style={{width: '500px', margin: 'auto'}}>
<Alert severity={alertSeverity} onClose={() => handleAlertClose}>
{message}
</Alert>
</div>: null;
};

return (
<>
{renderAlert()}
<ThemeProvider theme={theme}>
<Container component='main' maxWidth='xs'>
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'blue' }}>
<StorageIcon />
</Avatar>
<Typography component='h1' variant='h5'>
NutsDB
</Typography>
<Box component='form' onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
sx={{ width: '30ch', marginRight: '2ch' }}
margin='normal'
required
id='ip'
label='IP'
name='ip'
autoFocus
onChange={e => setIp(e.target.value)}
/>
<TextField
sx={{ width: '12ch' }}
margin='normal'
required
id='port'
label='Port'
name='port'
onChange={e => setPort(e.target.value)}
/>
<TextField
margin='normal'
required
fullWidth
id='alias'
label='Alias'
name='alias'
autoFocus
onChange={e => setAlias(e.target.value)}
/>
<TextField
margin='normal'
required
fullWidth
id='account'
label='Account'
name='account'
autoFocus
onChange={e => setAccount(e.target.value)}
/>
<TextField
margin='normal'
required
fullWidth
name='password'
label='Password'
type='password'
id='password'
autoComplete='current-password'
onChange={e => setPassword(e.target.value)}
/>
<FormControlLabel
control={<Checkbox value='remember' color='primary' />}
label='Remember me'
/>
<Button
type='submit'
fullWidth
variant='contained'
sx={{ mt: 3, mb: 2 }}
>
Connect
</Button>
</Box>
</Box>
</Box>
</Container>
</ThemeProvider>
</Container>
</ThemeProvider>
</>
);
}
}